@depup/artillery 2.0.30-depup.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +63 -0
- package/bin/run +29 -0
- package/bin/run.cmd +3 -0
- package/changes.json +138 -0
- package/console-reporter.js +1 -0
- package/lib/artillery-global.js +33 -0
- package/lib/cli/banner.js +8 -0
- package/lib/cli/common-flags.js +80 -0
- package/lib/cli/hooks/version.js +20 -0
- package/lib/cmds/dino.js +109 -0
- package/lib/cmds/quick.js +122 -0
- package/lib/cmds/report.js +34 -0
- package/lib/cmds/run-aci.js +91 -0
- package/lib/cmds/run-fargate.js +192 -0
- package/lib/cmds/run-lambda.js +96 -0
- package/lib/cmds/run.js +671 -0
- package/lib/console-capture.js +92 -0
- package/lib/console-reporter.js +438 -0
- package/lib/create-bom/built-in-plugins.js +12 -0
- package/lib/create-bom/create-bom.js +301 -0
- package/lib/dispatcher.js +9 -0
- package/lib/dist.js +222 -0
- package/lib/index.js +5 -0
- package/lib/launch-platform.js +439 -0
- package/lib/load-plugins.js +113 -0
- package/lib/platform/aws/aws-cloudwatch.js +106 -0
- package/lib/platform/aws/aws-create-sqs-queue.js +58 -0
- package/lib/platform/aws/aws-ensure-s3-bucket-exists.js +78 -0
- package/lib/platform/aws/aws-get-account-id.js +26 -0
- package/lib/platform/aws/aws-get-bucket-region.js +18 -0
- package/lib/platform/aws/aws-get-credentials.js +28 -0
- package/lib/platform/aws/aws-get-default-region.js +26 -0
- package/lib/platform/aws/aws-whoami.js +15 -0
- package/lib/platform/aws/constants.js +7 -0
- package/lib/platform/aws/iam-cf-templates/aws-iam-fargate-cf-template.yml +219 -0
- package/lib/platform/aws/iam-cf-templates/aws-iam-lambda-cf-template.yml +125 -0
- package/lib/platform/aws/iam-cf-templates/gh-oidc-fargate.yml +241 -0
- package/lib/platform/aws/iam-cf-templates/gh-oidc-lambda.yml +153 -0
- package/lib/platform/aws-ecs/ecs.js +247 -0
- package/lib/platform/aws-ecs/legacy/aws-util.js +134 -0
- package/lib/platform/aws-ecs/legacy/bom.js +528 -0
- package/lib/platform/aws-ecs/legacy/constants.js +27 -0
- package/lib/platform/aws-ecs/legacy/create-s3-client.js +24 -0
- package/lib/platform/aws-ecs/legacy/create-test.js +247 -0
- package/lib/platform/aws-ecs/legacy/errors.js +34 -0
- package/lib/platform/aws-ecs/legacy/find-public-subnets.js +149 -0
- package/lib/platform/aws-ecs/legacy/plugins/artillery-plugin-inspect-script/index.js +27 -0
- package/lib/platform/aws-ecs/legacy/plugins/artillery-plugin-sqs-reporter/azure-aqs.js +80 -0
- package/lib/platform/aws-ecs/legacy/plugins/artillery-plugin-sqs-reporter/index.js +202 -0
- package/lib/platform/aws-ecs/legacy/plugins.js +16 -0
- package/lib/platform/aws-ecs/legacy/run-cluster.js +1994 -0
- package/lib/platform/aws-ecs/legacy/sqs-reporter.js +401 -0
- package/lib/platform/aws-ecs/legacy/tags.js +22 -0
- package/lib/platform/aws-ecs/legacy/test-run-status.js +9 -0
- package/lib/platform/aws-ecs/legacy/time.js +67 -0
- package/lib/platform/aws-ecs/legacy/util.js +97 -0
- package/lib/platform/aws-ecs/worker/Dockerfile +64 -0
- package/lib/platform/aws-ecs/worker/helpers.sh +80 -0
- package/lib/platform/aws-ecs/worker/loadgen-worker +656 -0
- package/lib/platform/aws-lambda/dependencies.js +130 -0
- package/lib/platform/aws-lambda/index.js +734 -0
- package/lib/platform/aws-lambda/lambda-handler/a9-handler-dependencies.js +73 -0
- package/lib/platform/aws-lambda/lambda-handler/a9-handler-helpers.js +43 -0
- package/lib/platform/aws-lambda/lambda-handler/a9-handler-index.js +235 -0
- package/lib/platform/aws-lambda/lambda-handler/package.json +15 -0
- package/lib/platform/aws-lambda/prices.js +29 -0
- package/lib/platform/az/aci.js +694 -0
- package/lib/platform/az/aqs-queue-consumer.js +88 -0
- package/lib/platform/az/regions.js +52 -0
- package/lib/platform/cloud/api.js +72 -0
- package/lib/platform/cloud/cloud.js +448 -0
- package/lib/platform/cloud/http-client.js +19 -0
- package/lib/platform/local/artillery-worker-local.js +154 -0
- package/lib/platform/local/index.js +174 -0
- package/lib/platform/local/worker.js +261 -0
- package/lib/platform/worker-states.js +13 -0
- package/lib/queue-consumer/index.js +56 -0
- package/lib/stash.js +41 -0
- package/lib/telemetry.js +78 -0
- package/lib/util/await-on-ee.js +24 -0
- package/lib/util/generate-id.js +9 -0
- package/lib/util/parse-tag-string.js +21 -0
- package/lib/util/prepare-test-execution-plan.js +216 -0
- package/lib/util/sleep.js +7 -0
- package/lib/util/validate-script.js +132 -0
- package/lib/util.js +294 -0
- package/lib/utils-config.js +31 -0
- package/package.json +323 -0
- package/types.d.ts +317 -0
- package/util.js +1 -0
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
const debug = require('debug')('console-capture');
|
|
2
|
+
|
|
3
|
+
function setupConsoleCapture() {
|
|
4
|
+
let outputLines = [];
|
|
5
|
+
let truncated = false;
|
|
6
|
+
let currentSize = 0;
|
|
7
|
+
let sendFromIndex = 0;
|
|
8
|
+
|
|
9
|
+
const MAX_RETAINED_LOG_SIZE_MB = Number(
|
|
10
|
+
process.env.MAX_RETAINED_LOG_SIZE_MB || '50'
|
|
11
|
+
);
|
|
12
|
+
const MAX_RETAINED_LOG_SIZE = MAX_RETAINED_LOG_SIZE_MB * 1024 * 1024;
|
|
13
|
+
|
|
14
|
+
const interval = setInterval(() => {
|
|
15
|
+
if (!truncated && outputLines.length - sendFromIndex > 0) {
|
|
16
|
+
const newBatch = outputLines.slice(sendFromIndex, outputLines.length);
|
|
17
|
+
sendFromIndex = outputLines.length;
|
|
18
|
+
global.artillery.globalEvents.emit('logLines', newBatch, Date.now());
|
|
19
|
+
}
|
|
20
|
+
}, 10 * 1000).unref();
|
|
21
|
+
|
|
22
|
+
global.artillery.ext({
|
|
23
|
+
ext: 'onShutdown',
|
|
24
|
+
method: async () => {
|
|
25
|
+
debug('onBeforeExit', sendFromIndex, outputLines.length);
|
|
26
|
+
clearInterval(interval);
|
|
27
|
+
|
|
28
|
+
if (!truncated && sendFromIndex < outputLines.length) {
|
|
29
|
+
const ts = Date.now();
|
|
30
|
+
global.artillery.globalEvents.emit(
|
|
31
|
+
'logLines',
|
|
32
|
+
outputLines.slice(sendFromIndex, outputLines.length),
|
|
33
|
+
ts,
|
|
34
|
+
true
|
|
35
|
+
);
|
|
36
|
+
sendFromIndex = outputLines.length;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
console.log = (() => {
|
|
42
|
+
const orig = console.log;
|
|
43
|
+
return (...args) => {
|
|
44
|
+
try {
|
|
45
|
+
orig.apply(console, args);
|
|
46
|
+
|
|
47
|
+
if (currentSize < MAX_RETAINED_LOG_SIZE) {
|
|
48
|
+
outputLines = outputLines.concat([args]);
|
|
49
|
+
for (const x of args) {
|
|
50
|
+
currentSize += String(x).length;
|
|
51
|
+
}
|
|
52
|
+
} else {
|
|
53
|
+
if (!truncated) {
|
|
54
|
+
truncated = true;
|
|
55
|
+
const msg = `[WARNING] Artillery: maximum retained log size exceeded, max size: ${MAX_RETAINED_LOG_SIZE_MB}MB. Further logs won't be retained.\n\n`;
|
|
56
|
+
process.stdout.write(msg);
|
|
57
|
+
outputLines = outputLines.concat([msg]);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
} catch (err) {
|
|
61
|
+
debug(err);
|
|
62
|
+
}
|
|
63
|
+
};
|
|
64
|
+
})();
|
|
65
|
+
|
|
66
|
+
console.error = (() => {
|
|
67
|
+
const orig = console.error;
|
|
68
|
+
return (...args) => {
|
|
69
|
+
try {
|
|
70
|
+
orig.apply(console, args);
|
|
71
|
+
|
|
72
|
+
if (currentSize < MAX_RETAINED_LOG_SIZE) {
|
|
73
|
+
outputLines = outputLines.concat([args]);
|
|
74
|
+
for (const x of args) {
|
|
75
|
+
currentSize += String(x).length;
|
|
76
|
+
}
|
|
77
|
+
} else {
|
|
78
|
+
if (!truncated) {
|
|
79
|
+
truncated = true;
|
|
80
|
+
const msg = `[WARNING] Artillery: maximum retained log size exceeded, max size: ${MAX_RETAINED_LOG_SIZE_MB}MB. Further logs won't be retained.\n\n`;
|
|
81
|
+
process.stdout.write(msg);
|
|
82
|
+
outputLines = outputLines.concat([msg]);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
} catch (err) {
|
|
86
|
+
debug(err);
|
|
87
|
+
}
|
|
88
|
+
};
|
|
89
|
+
})();
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
module.exports = setupConsoleCapture;
|
|
@@ -0,0 +1,438 @@
|
|
|
1
|
+
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
2
|
+
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
3
|
+
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
const ora = require('ora');
|
|
8
|
+
const _ = require('lodash');
|
|
9
|
+
const moment = require('moment');
|
|
10
|
+
const chalk = require('chalk');
|
|
11
|
+
const Table = require('cli-table3');
|
|
12
|
+
const util = require('./util');
|
|
13
|
+
const SSMS = require('@artilleryio/int-core').ssms.SSMS;
|
|
14
|
+
|
|
15
|
+
module.exports = createConsoleReporter;
|
|
16
|
+
|
|
17
|
+
function createConsoleReporter(events, opts) {
|
|
18
|
+
const reporter = new ConsoleReporter(opts);
|
|
19
|
+
events.on('phaseStarted', reporter.phaseStarted.bind(reporter));
|
|
20
|
+
events.on('phaseCompleted', reporter.phaseCompleted.bind(reporter)); // TODO: Not firing - event not propagating?
|
|
21
|
+
events.on('stats', reporter.stats.bind(reporter));
|
|
22
|
+
events.on('done', reporter.done.bind(reporter));
|
|
23
|
+
reporter.start();
|
|
24
|
+
return reporter;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function ConsoleReporter(opts) {
|
|
28
|
+
this.opts = opts || {};
|
|
29
|
+
this.outputFormat = opts.outputFormat || process.env.OUTPUT_FORMAT || 'new';
|
|
30
|
+
|
|
31
|
+
this.quiet = opts.quiet;
|
|
32
|
+
this.metricsToSuppress = opts.metricsToSuppress;
|
|
33
|
+
this.spinner = ora({
|
|
34
|
+
spinner: 'dots'
|
|
35
|
+
});
|
|
36
|
+
this.spinner.start();
|
|
37
|
+
|
|
38
|
+
this.reportScenarioLatency = !!opts.reportScenarioLatency;
|
|
39
|
+
this.startTime = null;
|
|
40
|
+
|
|
41
|
+
global.artillery.globalEvents.on('log', (opts, ...args) => {
|
|
42
|
+
let logger;
|
|
43
|
+
if (typeof opts.level !== 'undefined' && opts.level !== 'info') {
|
|
44
|
+
logger = console.error;
|
|
45
|
+
} else {
|
|
46
|
+
logger = console.log;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
if (opts.showTimestamp) {
|
|
50
|
+
args.push(chalk.gray(`[${moment().format('HH:mm:ss')}]`));
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
this.spinner.clear();
|
|
54
|
+
logger.apply(console, [...args]);
|
|
55
|
+
this.spinner.start();
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
return this;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
ConsoleReporter.prototype.cleanup = function (done) {
|
|
62
|
+
this.spinner.clear();
|
|
63
|
+
return done(null);
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
ConsoleReporter.prototype.start = function start() {
|
|
67
|
+
if (this.quiet) {
|
|
68
|
+
return this;
|
|
69
|
+
}
|
|
70
|
+
// artillery.log(`Artillery running - ${moment(Date.now()).toISOString()}\n`);
|
|
71
|
+
return this;
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
ConsoleReporter.prototype.phaseStarted = function phaseStarted(phase) {
|
|
75
|
+
if (this.quiet) {
|
|
76
|
+
return this;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
const phaseDuration = phase.duration || phase.pause;
|
|
80
|
+
//only append s when phaseDuration is a number or number-like string (like from env variables). otherwise it's a converted unit (e.g. 5min)
|
|
81
|
+
const durationString = Number.isInteger(_.toNumber(phaseDuration)) ? `${phaseDuration}s` : `${phaseDuration}`;
|
|
82
|
+
|
|
83
|
+
artillery.log(
|
|
84
|
+
`Phase started: ${chalk.green(
|
|
85
|
+
phase.name ? phase.name : 'unnamed'
|
|
86
|
+
)} (index: ${phase.index}, duration: ${
|
|
87
|
+
durationString
|
|
88
|
+
}) ${formatTimestamp(new Date())}\n`
|
|
89
|
+
);
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
ConsoleReporter.prototype.phaseCompleted = function phaseCompleted(phase) {
|
|
93
|
+
if (this.quiet) {
|
|
94
|
+
return this;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
const phaseDuration = phase.duration || phase.pause;
|
|
98
|
+
//only append s when phaseDuration is a number or number-like string (like from env variables). otherwise it's a converted unit (e.g. 5min)
|
|
99
|
+
const durationString = Number.isInteger(_.toNumber(phaseDuration)) ? `${phaseDuration}s` : `${phaseDuration}`;
|
|
100
|
+
|
|
101
|
+
artillery.log(
|
|
102
|
+
`Phase completed: ${chalk.green(
|
|
103
|
+
phase.name ? phase.name : 'unnamed'
|
|
104
|
+
)} (index: ${phase.index}, duration: ${
|
|
105
|
+
durationString
|
|
106
|
+
}) ${formatTimestamp(new Date())}\n`
|
|
107
|
+
);
|
|
108
|
+
|
|
109
|
+
return this;
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
ConsoleReporter.prototype.stats = function stats(data) {
|
|
113
|
+
if (this.quiet) {
|
|
114
|
+
return this;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
if (!this.startTime) {
|
|
118
|
+
this.startTime = data.firstMetricAt || Date.now();
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// NOTE: histograms property is available and contains raw
|
|
122
|
+
// histogram objects
|
|
123
|
+
data.summaries = data.summaries || {};
|
|
124
|
+
data.counters = data.counters || {};
|
|
125
|
+
// data.rates = data.rates || {};
|
|
126
|
+
|
|
127
|
+
if (typeof data.report === 'function') {
|
|
128
|
+
// Compatibility fix with Artillery Pro which uses 1.x
|
|
129
|
+
// API for emitting reports to console-reporter.
|
|
130
|
+
// TODO: Remove when support for 1x is dropped in Artillery Pro
|
|
131
|
+
artillery.log(
|
|
132
|
+
`Elapsed time: ${util.formatDuration(Date.now() - this.startTime)}`
|
|
133
|
+
);
|
|
134
|
+
this.printReport(data.report(), this.opts);
|
|
135
|
+
} else {
|
|
136
|
+
this.printReport(data, this.opts);
|
|
137
|
+
}
|
|
138
|
+
artillery.log();
|
|
139
|
+
artillery.log();
|
|
140
|
+
};
|
|
141
|
+
|
|
142
|
+
ConsoleReporter.prototype.done = function done(data) {
|
|
143
|
+
if (this.quiet) {
|
|
144
|
+
return this;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
if (this.startTime !== null) {
|
|
148
|
+
artillery.log(
|
|
149
|
+
`All VUs finished. Total time: ${util.formatDuration(
|
|
150
|
+
Date.now() - this.startTime
|
|
151
|
+
)}\n`
|
|
152
|
+
);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
const txt = `Summary report @ ${formatTimestamp(new Date())}`;
|
|
156
|
+
artillery.log(`${underline(txt)}\n${txt}\n${underline(txt)}\n`);
|
|
157
|
+
|
|
158
|
+
// TODO: this is repeated in 'stats' handler
|
|
159
|
+
data.summaries = data.summaries || {};
|
|
160
|
+
data.counters = data.counters || {};
|
|
161
|
+
|
|
162
|
+
if (typeof data.report === 'function') {
|
|
163
|
+
// Compatibility fix with Artillery Pro which uses 1.x
|
|
164
|
+
// API for emitting reports to console-reporter.
|
|
165
|
+
// TODO: Remove when support for 1x is dropped in Artillery Pro
|
|
166
|
+
this.printReport(
|
|
167
|
+
data.report(),
|
|
168
|
+
Object.assign({}, this.opts, {
|
|
169
|
+
showScenarioCounts: true,
|
|
170
|
+
printPeriod: false
|
|
171
|
+
})
|
|
172
|
+
);
|
|
173
|
+
} else {
|
|
174
|
+
this.printReport(
|
|
175
|
+
data,
|
|
176
|
+
Object.assign({}, this.opts, {
|
|
177
|
+
showScenarioCounts: true,
|
|
178
|
+
printPeriod: false
|
|
179
|
+
})
|
|
180
|
+
);
|
|
181
|
+
}
|
|
182
|
+
};
|
|
183
|
+
|
|
184
|
+
ConsoleReporter.prototype.printReport = function printReport(report, opts) {
|
|
185
|
+
opts = opts || {};
|
|
186
|
+
if (opts.printPeriod !== false) {
|
|
187
|
+
const timeWindowEnd = moment(
|
|
188
|
+
new Date(Number(report.period) + 10 * 1000)
|
|
189
|
+
).format('HH:mm:ss(ZZ)');
|
|
190
|
+
if (typeof report.period !== 'undefined') {
|
|
191
|
+
// FIXME: up to bound should be included in the report
|
|
192
|
+
// Add underline
|
|
193
|
+
const txt = `Metrics for period to: ${timeWindowEnd}`;
|
|
194
|
+
artillery.log(
|
|
195
|
+
underline(txt) +
|
|
196
|
+
'\n' +
|
|
197
|
+
txt +
|
|
198
|
+
' ' +
|
|
199
|
+
chalk.gray(
|
|
200
|
+
'(width: ' +
|
|
201
|
+
(report.lastMetricAt - report.firstMetricAt) / 1000 +
|
|
202
|
+
's)'
|
|
203
|
+
) +
|
|
204
|
+
'\n' +
|
|
205
|
+
underline(txt) +
|
|
206
|
+
'\n'
|
|
207
|
+
);
|
|
208
|
+
|
|
209
|
+
// artillery.log(padded('time_window:', timeWindowEnd));
|
|
210
|
+
} else {
|
|
211
|
+
artillery.log('Report @ %s', formatTimestamp(report.timestamp));
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
if (this.outputFormat === 'new') {
|
|
216
|
+
report.rates = report.rates || {};
|
|
217
|
+
report.counters = report.counters || {};
|
|
218
|
+
report.summaries = report.summaries || {};
|
|
219
|
+
|
|
220
|
+
const sortedByLen = _(
|
|
221
|
+
Object.keys(report.summaries)
|
|
222
|
+
.concat(Object.keys(report.counters))
|
|
223
|
+
.concat(Object.keys(report.rates))
|
|
224
|
+
)
|
|
225
|
+
.sortBy([(x) => x.length])
|
|
226
|
+
.value();
|
|
227
|
+
|
|
228
|
+
if (sortedByLen.length === 0) {
|
|
229
|
+
// No scenarios launched or completed, no requests made or completed etc. Nothing happened.
|
|
230
|
+
artillery.log('No measurements recorded during this period');
|
|
231
|
+
return;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
const sortedAlphabetically = sortedByLen.sort();
|
|
235
|
+
|
|
236
|
+
let result = [];
|
|
237
|
+
for (const metricName of sortedAlphabetically) {
|
|
238
|
+
|
|
239
|
+
if (shouldSuppressOutput(metricName, this.metricsToSuppress)) {
|
|
240
|
+
continue;
|
|
241
|
+
};
|
|
242
|
+
if (typeof report.counters?.[metricName] !== 'undefined') {
|
|
243
|
+
result = result.concat(printCounters([metricName], report));
|
|
244
|
+
}
|
|
245
|
+
if (typeof report.summaries?.[metricName] !== 'undefined') {
|
|
246
|
+
result = result.concat(printSummaries([metricName], report));
|
|
247
|
+
}
|
|
248
|
+
if (typeof report.rates?.[metricName] !== 'undefined') {
|
|
249
|
+
result = result.concat(printRates([metricName], report));
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
artillery.log(result.join('\n'));
|
|
254
|
+
}
|
|
255
|
+
};
|
|
256
|
+
|
|
257
|
+
if (this.outputFormat === 'classic') {
|
|
258
|
+
report = SSMS.legacyReport(report).report();
|
|
259
|
+
|
|
260
|
+
// TODO: Read new fields instead of the old ones
|
|
261
|
+
|
|
262
|
+
artillery.log('Scenarios launched: %s', report.scenariosCreated);
|
|
263
|
+
artillery.log('Scenarios completed: %s', report.scenariosCompleted);
|
|
264
|
+
artillery.log('Requests completed: %s', report.requestsCompleted);
|
|
265
|
+
|
|
266
|
+
artillery.log('Mean responses/sec: %s', report.rps.mean);
|
|
267
|
+
artillery.log('Response time (msec):');
|
|
268
|
+
artillery.log(' min: %s', report.latency.min);
|
|
269
|
+
artillery.log(' max: %s', report.latency.max);
|
|
270
|
+
artillery.log(' median: %s', report.latency.median);
|
|
271
|
+
artillery.log(' p95: %s', report.latency.p95);
|
|
272
|
+
artillery.log(' p99: %s', report.latency.p99);
|
|
273
|
+
|
|
274
|
+
if (this.reportScenarioLatency) {
|
|
275
|
+
artillery.log('Scenario duration:');
|
|
276
|
+
artillery.log(' min: %s', report.scenarioDuration.min);
|
|
277
|
+
artillery.log(' max: %s', report.scenarioDuration.max);
|
|
278
|
+
artillery.log(' median: %s', report.scenarioDuration.median);
|
|
279
|
+
artillery.log(' p95: %s', report.scenarioDuration.p95);
|
|
280
|
+
artillery.log(' p99: %s', report.scenarioDuration.p99);
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
// We only want to show this for the aggregate report:
|
|
284
|
+
if (opts.showScenarioCounts && report.scenarioCounts) {
|
|
285
|
+
artillery.log('Scenario counts:');
|
|
286
|
+
_.each(report.scenarioCounts, (count, name) => {
|
|
287
|
+
const percentage =
|
|
288
|
+
Math.round((count / report.scenariosCreated) * 100 * 1000) / 1000;
|
|
289
|
+
artillery.log(' %s: %s (%s%)', name, count, percentage);
|
|
290
|
+
});
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
if (_.keys(report.codes).length !== 0) {
|
|
294
|
+
artillery.log('Codes:');
|
|
295
|
+
_.each(report.codes, (count, code) => {
|
|
296
|
+
artillery.log(' %s: %s', code, count);
|
|
297
|
+
});
|
|
298
|
+
}
|
|
299
|
+
if (_.keys(report.errors).length !== 0) {
|
|
300
|
+
artillery.log('Errors:');
|
|
301
|
+
_.each(report.errors, (count, code) => {
|
|
302
|
+
artillery.log(' %s: %s', code, count);
|
|
303
|
+
});
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
if (_.size(report.summaries) > 0 || _.size(report.counters) > 0) {
|
|
307
|
+
_.each(report.summaries, (r, n) => {
|
|
308
|
+
if (excludeFromReporting(n)) return;
|
|
309
|
+
|
|
310
|
+
artillery.log('%s:', n);
|
|
311
|
+
artillery.log(' min: %s', r.min);
|
|
312
|
+
artillery.log(' max: %s', r.max);
|
|
313
|
+
artillery.log(' median: %s', r.median);
|
|
314
|
+
artillery.log(' p95: %s', r.p95);
|
|
315
|
+
artillery.log(' p99: %s', r.p99);
|
|
316
|
+
});
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
_.each(report.customStats, (r, n) => {
|
|
320
|
+
artillery.log('%s:', n);
|
|
321
|
+
artillery.log(' min: %s', r.min);
|
|
322
|
+
artillery.log(' max: %s', r.max);
|
|
323
|
+
artillery.log(' median: %s', r.median);
|
|
324
|
+
artillery.log(' p95: %s', r.p95);
|
|
325
|
+
artillery.log(' p99: %s', r.p99);
|
|
326
|
+
});
|
|
327
|
+
|
|
328
|
+
_.each(report.counters, (value, name) => {
|
|
329
|
+
// Only show user/custom metrics in this mode, but none of the internally generated ones:
|
|
330
|
+
if (excludeFromReporting(name)) return;
|
|
331
|
+
artillery.log('%s: %s', name, value);
|
|
332
|
+
});
|
|
333
|
+
|
|
334
|
+
artillery.log();
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
function isCollectionMetric(n) {
|
|
338
|
+
const collectionMetrics = ['artillery.codes', 'errors'];
|
|
339
|
+
return (
|
|
340
|
+
collectionMetrics.filter((m) => {
|
|
341
|
+
return n.startsWith(m);
|
|
342
|
+
}).length > 0
|
|
343
|
+
);
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
if (this.outputFormat === 'table') {
|
|
347
|
+
const t = new Table({ head: ['Metric', 'Value'] });
|
|
348
|
+
|
|
349
|
+
if (_.size(report.summaries) > 0 || _.size(report.counters) > 0) {
|
|
350
|
+
_.sortBy(Object.keys(report.summaries)).forEach((n) => {
|
|
351
|
+
const r = report.summaries[n];
|
|
352
|
+
const spaces = ' '.repeat(Math.min(8, n.length + 1));
|
|
353
|
+
t.push([`${n}`]);
|
|
354
|
+
t.push([`${spaces}min`, r.min]);
|
|
355
|
+
t.push([`${spaces}max`, r.max]);
|
|
356
|
+
t.push([`${spaces}median`, r.median]);
|
|
357
|
+
t.push([`${spaces}p95`, r.p95]);
|
|
358
|
+
t.push([`${spaces}p99`, r.p99]);
|
|
359
|
+
});
|
|
360
|
+
|
|
361
|
+
_.sortBy(
|
|
362
|
+
Object.keys(report.counters).filter((name) => !isCollectionMetric(name))
|
|
363
|
+
).forEach((name) => {
|
|
364
|
+
const value = report.counters[name];
|
|
365
|
+
t.push([name, value]);
|
|
366
|
+
});
|
|
367
|
+
}
|
|
368
|
+
artillery.log(t.toString());
|
|
369
|
+
artillery.log();
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
// TODO: Make smarter if date changes, ie. test runs over midnight
|
|
373
|
+
function formatTimestamp(timestamp) {
|
|
374
|
+
return moment(new Date(timestamp)).format('HH:mm:ss(ZZ)');
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
function underline(text) {
|
|
378
|
+
return '-'.repeat(text.length);
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
function excludeFromReporting(name) {
|
|
382
|
+
return (
|
|
383
|
+
['engine', 'core', 'artillery', 'errors', 'scenarios'].indexOf(
|
|
384
|
+
name.split('.')[0]
|
|
385
|
+
) > -1
|
|
386
|
+
);
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
function padded(str1, str2) {
|
|
390
|
+
const defaultWidth = 79;
|
|
391
|
+
// We need at least 50
|
|
392
|
+
const columnsAvailable = Math.max(
|
|
393
|
+
process.stdout?.columns || defaultWidth,
|
|
394
|
+
50
|
|
395
|
+
);
|
|
396
|
+
// But no more than 79:
|
|
397
|
+
const width = Math.min(columnsAvailable, defaultWidth);
|
|
398
|
+
|
|
399
|
+
return util.padded(str1, str2, width);
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
function printRates(rates, report) {
|
|
403
|
+
return rates.sort().map((name) => {
|
|
404
|
+
return `${padded(`${name}:`, report.rates[name])}/sec`;
|
|
405
|
+
});
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
function printCounters(counters, report) {
|
|
409
|
+
return counters.sort().map((name) => {
|
|
410
|
+
const value = report.counters[name];
|
|
411
|
+
return padded(`${name}:`, value);
|
|
412
|
+
});
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
function printSummaries(summaries, report) {
|
|
416
|
+
const result = [];
|
|
417
|
+
for (const n of summaries) {
|
|
418
|
+
const r = report.summaries[n];
|
|
419
|
+
result.push(`${n}:`);
|
|
420
|
+
result.push(padded(' min:', r.min));
|
|
421
|
+
result.push(padded(' max:', r.max));
|
|
422
|
+
result.push(padded(' mean:', r.mean));
|
|
423
|
+
result.push(padded(' median:', r.median));
|
|
424
|
+
result.push(padded(' p95:', r.p95));
|
|
425
|
+
result.push(padded(' p99:', r.p99));
|
|
426
|
+
|
|
427
|
+
// TODO: Can work well if padded to look like a table:
|
|
428
|
+
// result.push(padded(`${trimName(n)}:`, `min: ${r.min} | max: ${r.max} | p50: ${r.p50} | p95: ${r.p95} | p99: ${r.p99}`));
|
|
429
|
+
}
|
|
430
|
+
return result;
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
function shouldSuppressOutput(currMetricName, suppressMetricsList) {
|
|
434
|
+
if (!suppressMetricsList) {
|
|
435
|
+
return;
|
|
436
|
+
};
|
|
437
|
+
return suppressMetricsList.some((metric)=> currMetricName.includes(metric));
|
|
438
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
2
|
+
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
3
|
+
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
4
|
+
|
|
5
|
+
module.exports = [
|
|
6
|
+
'metrics-by-endpoint',
|
|
7
|
+
'ensure',
|
|
8
|
+
'publish-metrics',
|
|
9
|
+
'expect',
|
|
10
|
+
'apdex',
|
|
11
|
+
'slack'
|
|
12
|
+
];
|