@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.
Files changed (90) hide show
  1. package/README.md +63 -0
  2. package/bin/run +29 -0
  3. package/bin/run.cmd +3 -0
  4. package/changes.json +138 -0
  5. package/console-reporter.js +1 -0
  6. package/lib/artillery-global.js +33 -0
  7. package/lib/cli/banner.js +8 -0
  8. package/lib/cli/common-flags.js +80 -0
  9. package/lib/cli/hooks/version.js +20 -0
  10. package/lib/cmds/dino.js +109 -0
  11. package/lib/cmds/quick.js +122 -0
  12. package/lib/cmds/report.js +34 -0
  13. package/lib/cmds/run-aci.js +91 -0
  14. package/lib/cmds/run-fargate.js +192 -0
  15. package/lib/cmds/run-lambda.js +96 -0
  16. package/lib/cmds/run.js +671 -0
  17. package/lib/console-capture.js +92 -0
  18. package/lib/console-reporter.js +438 -0
  19. package/lib/create-bom/built-in-plugins.js +12 -0
  20. package/lib/create-bom/create-bom.js +301 -0
  21. package/lib/dispatcher.js +9 -0
  22. package/lib/dist.js +222 -0
  23. package/lib/index.js +5 -0
  24. package/lib/launch-platform.js +439 -0
  25. package/lib/load-plugins.js +113 -0
  26. package/lib/platform/aws/aws-cloudwatch.js +106 -0
  27. package/lib/platform/aws/aws-create-sqs-queue.js +58 -0
  28. package/lib/platform/aws/aws-ensure-s3-bucket-exists.js +78 -0
  29. package/lib/platform/aws/aws-get-account-id.js +26 -0
  30. package/lib/platform/aws/aws-get-bucket-region.js +18 -0
  31. package/lib/platform/aws/aws-get-credentials.js +28 -0
  32. package/lib/platform/aws/aws-get-default-region.js +26 -0
  33. package/lib/platform/aws/aws-whoami.js +15 -0
  34. package/lib/platform/aws/constants.js +7 -0
  35. package/lib/platform/aws/iam-cf-templates/aws-iam-fargate-cf-template.yml +219 -0
  36. package/lib/platform/aws/iam-cf-templates/aws-iam-lambda-cf-template.yml +125 -0
  37. package/lib/platform/aws/iam-cf-templates/gh-oidc-fargate.yml +241 -0
  38. package/lib/platform/aws/iam-cf-templates/gh-oidc-lambda.yml +153 -0
  39. package/lib/platform/aws-ecs/ecs.js +247 -0
  40. package/lib/platform/aws-ecs/legacy/aws-util.js +134 -0
  41. package/lib/platform/aws-ecs/legacy/bom.js +528 -0
  42. package/lib/platform/aws-ecs/legacy/constants.js +27 -0
  43. package/lib/platform/aws-ecs/legacy/create-s3-client.js +24 -0
  44. package/lib/platform/aws-ecs/legacy/create-test.js +247 -0
  45. package/lib/platform/aws-ecs/legacy/errors.js +34 -0
  46. package/lib/platform/aws-ecs/legacy/find-public-subnets.js +149 -0
  47. package/lib/platform/aws-ecs/legacy/plugins/artillery-plugin-inspect-script/index.js +27 -0
  48. package/lib/platform/aws-ecs/legacy/plugins/artillery-plugin-sqs-reporter/azure-aqs.js +80 -0
  49. package/lib/platform/aws-ecs/legacy/plugins/artillery-plugin-sqs-reporter/index.js +202 -0
  50. package/lib/platform/aws-ecs/legacy/plugins.js +16 -0
  51. package/lib/platform/aws-ecs/legacy/run-cluster.js +1994 -0
  52. package/lib/platform/aws-ecs/legacy/sqs-reporter.js +401 -0
  53. package/lib/platform/aws-ecs/legacy/tags.js +22 -0
  54. package/lib/platform/aws-ecs/legacy/test-run-status.js +9 -0
  55. package/lib/platform/aws-ecs/legacy/time.js +67 -0
  56. package/lib/platform/aws-ecs/legacy/util.js +97 -0
  57. package/lib/platform/aws-ecs/worker/Dockerfile +64 -0
  58. package/lib/platform/aws-ecs/worker/helpers.sh +80 -0
  59. package/lib/platform/aws-ecs/worker/loadgen-worker +656 -0
  60. package/lib/platform/aws-lambda/dependencies.js +130 -0
  61. package/lib/platform/aws-lambda/index.js +734 -0
  62. package/lib/platform/aws-lambda/lambda-handler/a9-handler-dependencies.js +73 -0
  63. package/lib/platform/aws-lambda/lambda-handler/a9-handler-helpers.js +43 -0
  64. package/lib/platform/aws-lambda/lambda-handler/a9-handler-index.js +235 -0
  65. package/lib/platform/aws-lambda/lambda-handler/package.json +15 -0
  66. package/lib/platform/aws-lambda/prices.js +29 -0
  67. package/lib/platform/az/aci.js +694 -0
  68. package/lib/platform/az/aqs-queue-consumer.js +88 -0
  69. package/lib/platform/az/regions.js +52 -0
  70. package/lib/platform/cloud/api.js +72 -0
  71. package/lib/platform/cloud/cloud.js +448 -0
  72. package/lib/platform/cloud/http-client.js +19 -0
  73. package/lib/platform/local/artillery-worker-local.js +154 -0
  74. package/lib/platform/local/index.js +174 -0
  75. package/lib/platform/local/worker.js +261 -0
  76. package/lib/platform/worker-states.js +13 -0
  77. package/lib/queue-consumer/index.js +56 -0
  78. package/lib/stash.js +41 -0
  79. package/lib/telemetry.js +78 -0
  80. package/lib/util/await-on-ee.js +24 -0
  81. package/lib/util/generate-id.js +9 -0
  82. package/lib/util/parse-tag-string.js +21 -0
  83. package/lib/util/prepare-test-execution-plan.js +216 -0
  84. package/lib/util/sleep.js +7 -0
  85. package/lib/util/validate-script.js +132 -0
  86. package/lib/util.js +294 -0
  87. package/lib/utils-config.js +31 -0
  88. package/package.json +323 -0
  89. package/types.d.ts +317 -0
  90. 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
+ ];