k6-perf-reporter 1.0.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 (113) hide show
  1. package/.claude/settings.local.json +54 -0
  2. package/.config.example.json +8 -0
  3. package/.config.json +8 -0
  4. package/.eslintrc.json +18 -0
  5. package/.github/workflows/build.yml +30 -0
  6. package/.github/workflows/release.yml +44 -0
  7. package/README.md +449 -0
  8. package/dist/cli-reporter.d.ts +5 -0
  9. package/dist/cli-reporter.d.ts.map +1 -0
  10. package/dist/cli-reporter.js +71 -0
  11. package/dist/cli-reporter.js.map +1 -0
  12. package/dist/cli.d.ts +2 -0
  13. package/dist/cli.d.ts.map +1 -0
  14. package/dist/cli.js +43 -0
  15. package/dist/cli.js.map +1 -0
  16. package/dist/config.d.ts +14 -0
  17. package/dist/config.d.ts.map +1 -0
  18. package/dist/config.js +26 -0
  19. package/dist/config.js.map +1 -0
  20. package/dist/data-collector.d.ts +14 -0
  21. package/dist/data-collector.d.ts.map +1 -0
  22. package/dist/data-collector.js +51 -0
  23. package/dist/data-collector.js.map +1 -0
  24. package/dist/data-extractor.d.ts +31 -0
  25. package/dist/data-extractor.d.ts.map +1 -0
  26. package/dist/data-extractor.js +250 -0
  27. package/dist/data-extractor.js.map +1 -0
  28. package/dist/explore.d.ts +2 -0
  29. package/dist/explore.d.ts.map +1 -0
  30. package/dist/explore.js +27 -0
  31. package/dist/explore.js.map +1 -0
  32. package/dist/index.d.ts +7 -0
  33. package/dist/index.d.ts.map +1 -0
  34. package/dist/index.js +43 -0
  35. package/dist/index.js.map +1 -0
  36. package/dist/influx-client.d.ts +16 -0
  37. package/dist/influx-client.d.ts.map +1 -0
  38. package/dist/influx-client.interface.d.ts +21 -0
  39. package/dist/influx-client.interface.d.ts.map +1 -0
  40. package/dist/influx-client.interface.js +3 -0
  41. package/dist/influx-client.interface.js.map +1 -0
  42. package/dist/influx-client.js +35 -0
  43. package/dist/influx-client.js.map +1 -0
  44. package/dist/influx-data-extractor.d.ts +112 -0
  45. package/dist/influx-data-extractor.d.ts.map +1 -0
  46. package/dist/influx-data-extractor.interface.d.ts +21 -0
  47. package/dist/influx-data-extractor.interface.d.ts.map +1 -0
  48. package/dist/influx-data-extractor.interface.js +3 -0
  49. package/dist/influx-data-extractor.interface.js.map +1 -0
  50. package/dist/influx-data-extractor.js +445 -0
  51. package/dist/influx-data-extractor.js.map +1 -0
  52. package/dist/influx.d.ts +122 -0
  53. package/dist/influx.d.ts.map +1 -0
  54. package/dist/influx.js +899 -0
  55. package/dist/influx.js.map +1 -0
  56. package/dist/logger.d.ts +7 -0
  57. package/dist/logger.d.ts.map +1 -0
  58. package/dist/logger.js +12 -0
  59. package/dist/logger.js.map +1 -0
  60. package/dist/metrics-collector.d.ts +10 -0
  61. package/dist/metrics-collector.d.ts.map +1 -0
  62. package/dist/metrics-collector.js +99 -0
  63. package/dist/metrics-collector.js.map +1 -0
  64. package/dist/metrics-collector.test.d.ts +2 -0
  65. package/dist/metrics-collector.test.d.ts.map +1 -0
  66. package/dist/metrics-collector.test.js +235 -0
  67. package/dist/metrics-collector.test.js.map +1 -0
  68. package/dist/reporters/cli-reporter.d.ts +9 -0
  69. package/dist/reporters/cli-reporter.d.ts.map +1 -0
  70. package/dist/reporters/cli-reporter.js +141 -0
  71. package/dist/reporters/cli-reporter.js.map +1 -0
  72. package/dist/reporters/cli.d.ts +5 -0
  73. package/dist/reporters/cli.d.ts.map +1 -0
  74. package/dist/reporters/cli.js +150 -0
  75. package/dist/reporters/cli.js.map +1 -0
  76. package/dist/reporters/index.d.ts +3 -0
  77. package/dist/reporters/index.d.ts.map +1 -0
  78. package/dist/reporters/index.js +8 -0
  79. package/dist/reporters/index.js.map +1 -0
  80. package/dist/reporters/json-reporter.d.ts +5 -0
  81. package/dist/reporters/json-reporter.d.ts.map +1 -0
  82. package/dist/reporters/json-reporter.js +18 -0
  83. package/dist/reporters/json-reporter.js.map +1 -0
  84. package/dist/reporters/json.d.ts +5 -0
  85. package/dist/reporters/json.d.ts.map +1 -0
  86. package/dist/reporters/json.js +70 -0
  87. package/dist/reporters/json.js.map +1 -0
  88. package/dist/reporters/markdown.d.ts +5 -0
  89. package/dist/reporters/markdown.d.ts.map +1 -0
  90. package/dist/reporters/markdown.js +87 -0
  91. package/dist/reporters/markdown.js.map +1 -0
  92. package/dist/reports.d.ts +11 -0
  93. package/dist/reports.d.ts.map +1 -0
  94. package/dist/reports.js +325 -0
  95. package/dist/reports.js.map +1 -0
  96. package/dist/types.d.ts +113 -0
  97. package/dist/types.d.ts.map +1 -0
  98. package/dist/types.js +4 -0
  99. package/dist/types.js.map +1 -0
  100. package/dist/utils.d.ts +2 -0
  101. package/dist/utils.d.ts.map +1 -0
  102. package/dist/utils.js +19 -0
  103. package/dist/utils.js.map +1 -0
  104. package/package.json +33 -0
  105. package/src/cli.ts +47 -0
  106. package/src/config.ts +31 -0
  107. package/src/data-collector.ts +66 -0
  108. package/src/influx-client.ts +48 -0
  109. package/src/influx-data-extractor.ts +722 -0
  110. package/src/reporters/cli-reporter.ts +169 -0
  111. package/src/reporters/index.ts +2 -0
  112. package/src/reporters/json-reporter.ts +15 -0
  113. package/tsconfig.json +20 -0
@@ -0,0 +1,325 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.ReportGenerator = void 0;
7
+ const chalk_1 = __importDefault(require("chalk"));
8
+ class ReportGenerator {
9
+ constructor(influxClient) {
10
+ this.influxClient = influxClient;
11
+ }
12
+ async generateMetrics(scenario, startTime, endTime) {
13
+ console.log(chalk_1.default.blue(` 📍 Fetching metrics for scenario: ${chalk_1.default.bold(scenario)}`));
14
+ console.log(chalk_1.default.gray(` Time range: ${startTime} to ${endTime}`));
15
+ try {
16
+ console.log(chalk_1.default.gray(" ├─ Querying response time percentiles..."));
17
+ const startPercentilesTime = Date.now();
18
+ const percentiles = await this.influxClient.getResponseTimePercentiles(scenario, startTime, endTime);
19
+ const percentilesDuration = Date.now() - startPercentilesTime;
20
+ console.log(chalk_1.default.green(` ├─ ✓ Response times: P50=${percentiles.p50.toFixed(2)}ms, P95=${percentiles.p95.toFixed(2)}ms, P99=${percentiles.p99.toFixed(2)}ms (${percentilesDuration}ms)`));
21
+ console.log(chalk_1.default.gray(" ├─ Querying request statistics..."));
22
+ const startStatsTime = Date.now();
23
+ const stats = await this.influxClient.getRequestStats(scenario, startTime, endTime);
24
+ const statsDuration = Date.now() - startStatsTime;
25
+ console.log(chalk_1.default.green(` ├─ ✓ Requests: total=${stats.total}, success=${stats.success}, failed=${stats.failed} (${statsDuration}ms)`));
26
+ console.log(chalk_1.default.gray(" └─ Querying error breakdown..."));
27
+ const startErrorsTime = Date.now();
28
+ const errors = await this.influxClient.getErrorBreakdown(scenario, startTime, endTime);
29
+ const errorsDuration = Date.now() - startErrorsTime;
30
+ const errorCount = Array.from(errors.values()).reduce((sum, count) => sum + count, 0);
31
+ console.log(chalk_1.default.green(` └─ ✓ Errors: ${errors.size} unique error types, ${errorCount} total errors (${errorsDuration}ms)`));
32
+ const successRate = stats.total
33
+ ? (stats.success / stats.total) * 100
34
+ : 0;
35
+ const errorRate = 100 - successRate;
36
+ // Calculate throughput (requests per second)
37
+ const startDate = new Date(startTime);
38
+ const endDate = new Date(endTime);
39
+ const durationSeconds = (endDate.getTime() - startDate.getTime()) / 1000 || 1;
40
+ const throughput = stats.total / durationSeconds;
41
+ console.log(chalk_1.default.blue(` 📊 Metrics summary: Error rate=${errorRate.toFixed(2)}%, Throughput=${throughput.toFixed(2)} req/s`));
42
+ return {
43
+ responseTimeP50: percentiles.p50,
44
+ responseTimeP95: percentiles.p95,
45
+ responseTimeP99: percentiles.p99,
46
+ throughput,
47
+ totalRequests: stats.total,
48
+ successfulRequests: stats.success,
49
+ failedRequests: stats.failed,
50
+ errorRate,
51
+ errors,
52
+ };
53
+ }
54
+ catch (error) {
55
+ console.error(chalk_1.default.red(" ❌ Error fetching metrics:"), error instanceof Error ? error.message : error);
56
+ throw error;
57
+ }
58
+ }
59
+ generateHTMLReport(metrics, testName) {
60
+ const errorRows = Array.from(metrics.errors.entries())
61
+ .map(([error, count]) => `<tr><td>${error}</td><td>${count}</td></tr>`)
62
+ .join("");
63
+ const html = `
64
+ <!DOCTYPE html>
65
+ <html lang="en">
66
+ <head>
67
+ <meta charset="UTF-8">
68
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
69
+ <title>k6 Test Report - ${testName}</title>
70
+ <style>
71
+ * { margin: 0; padding: 0; box-sizing: border-box; }
72
+ body {
73
+ font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
74
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
75
+ min-height: 100vh;
76
+ padding: 20px;
77
+ }
78
+ .container {
79
+ max-width: 1200px;
80
+ margin: 0 auto;
81
+ background: white;
82
+ border-radius: 12px;
83
+ box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3);
84
+ overflow: hidden;
85
+ }
86
+ .header {
87
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
88
+ color: white;
89
+ padding: 40px 30px;
90
+ text-align: center;
91
+ }
92
+ .header h1 {
93
+ font-size: 2.5em;
94
+ margin-bottom: 10px;
95
+ }
96
+ .header p {
97
+ font-size: 1.1em;
98
+ opacity: 0.9;
99
+ }
100
+ .content {
101
+ padding: 40px;
102
+ }
103
+ .metrics-grid {
104
+ display: grid;
105
+ grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
106
+ gap: 20px;
107
+ margin-bottom: 40px;
108
+ }
109
+ .metric-card {
110
+ background: #f8f9fa;
111
+ border-left: 4px solid #667eea;
112
+ padding: 20px;
113
+ border-radius: 8px;
114
+ transition: transform 0.2s, box-shadow 0.2s;
115
+ }
116
+ .metric-card:hover {
117
+ transform: translateY(-5px);
118
+ box-shadow: 0 10px 25px rgba(0, 0, 0, 0.1);
119
+ }
120
+ .metric-card.warning {
121
+ border-left-color: #f59e0b;
122
+ }
123
+ .metric-card.danger {
124
+ border-left-color: #ef4444;
125
+ }
126
+ .metric-label {
127
+ font-size: 0.85em;
128
+ color: #6b7280;
129
+ text-transform: uppercase;
130
+ letter-spacing: 0.5px;
131
+ margin-bottom: 8px;
132
+ font-weight: 600;
133
+ }
134
+ .metric-value {
135
+ font-size: 2em;
136
+ font-weight: bold;
137
+ color: #1f2937;
138
+ }
139
+ .metric-unit {
140
+ font-size: 0.6em;
141
+ color: #9ca3af;
142
+ margin-left: 4px;
143
+ }
144
+ .section-title {
145
+ font-size: 1.5em;
146
+ font-weight: bold;
147
+ color: #1f2937;
148
+ margin-bottom: 20px;
149
+ padding-bottom: 10px;
150
+ border-bottom: 2px solid #667eea;
151
+ }
152
+ table {
153
+ width: 100%;
154
+ border-collapse: collapse;
155
+ margin-top: 15px;
156
+ }
157
+ th {
158
+ background: #f3f4f6;
159
+ padding: 12px;
160
+ text-align: left;
161
+ font-weight: 600;
162
+ color: #374151;
163
+ border-bottom: 2px solid #e5e7eb;
164
+ }
165
+ td {
166
+ padding: 12px;
167
+ border-bottom: 1px solid #e5e7eb;
168
+ }
169
+ tr:hover {
170
+ background: #f9fafb;
171
+ }
172
+ .footer {
173
+ background: #f3f4f6;
174
+ padding: 20px 40px;
175
+ text-align: center;
176
+ color: #6b7280;
177
+ font-size: 0.9em;
178
+ }
179
+ .status-badge {
180
+ display: inline-block;
181
+ padding: 6px 12px;
182
+ border-radius: 20px;
183
+ font-size: 0.85em;
184
+ font-weight: 600;
185
+ }
186
+ .status-badge.pass {
187
+ background: #d1fae5;
188
+ color: #065f46;
189
+ }
190
+ .status-badge.fail {
191
+ background: #fee2e2;
192
+ color: #991b1b;
193
+ }
194
+ </style>
195
+ </head>
196
+ <body>
197
+ <div class="container">
198
+ <div class="header">
199
+ <h1>k6 Performance Test Report</h1>
200
+ <p>${testName}</p>
201
+ <p style="font-size: 0.9em; margin-top: 10px;">${new Date().toLocaleString()}</p>
202
+ </div>
203
+
204
+ <div class="content">
205
+ <div class="metrics-grid">
206
+ <div class="metric-card">
207
+ <div class="metric-label">Response Time (p50)</div>
208
+ <div class="metric-value">${metrics.responseTimeP50.toFixed(2)}<span class="metric-unit">ms</span></div>
209
+ </div>
210
+ <div class="metric-card">
211
+ <div class="metric-label">Response Time (p95)</div>
212
+ <div class="metric-value">${metrics.responseTimeP95.toFixed(2)}<span class="metric-unit">ms</span></div>
213
+ </div>
214
+ <div class="metric-card">
215
+ <div class="metric-label">Response Time (p99)</div>
216
+ <div class="metric-value">${metrics.responseTimeP99.toFixed(2)}<span class="metric-unit">ms</span></div>
217
+ </div>
218
+ <div class="metric-card">
219
+ <div class="metric-label">Throughput</div>
220
+ <div class="metric-value">${metrics.throughput.toFixed(2)}<span class="metric-unit">req/s</span></div>
221
+ </div>
222
+ <div class="metric-card">
223
+ <div class="metric-label">Total Requests</div>
224
+ <div class="metric-value">${metrics.totalRequests}</div>
225
+ </div>
226
+ <div class="metric-card ${metrics.errorRate > 5 ? "warning" : ""} ${metrics.errorRate > 10 ? "danger" : ""}">
227
+ <div class="metric-label">Error Rate</div>
228
+ <div class="metric-value">${metrics.errorRate.toFixed(2)}<span class="metric-unit">%</span></div>
229
+ </div>
230
+ <div class="metric-card">
231
+ <div class="metric-label">Successful Requests</div>
232
+ <div class="metric-value">${metrics.successfulRequests}</div>
233
+ </div>
234
+ <div class="metric-card ${metrics.failedRequests > 0 ? "danger" : ""}">
235
+ <div class="metric-label">Failed Requests</div>
236
+ <div class="metric-value">${metrics.failedRequests}</div>
237
+ </div>
238
+ </div>
239
+
240
+ <div class="section-title">Summary</div>
241
+ <div style="background: #f9fafb; padding: 20px; border-radius: 8px; margin-bottom: 30px;">
242
+ <p><strong>Test Name:</strong> ${testName}</p>
243
+ <p><strong>Status:</strong> ${metrics.errorRate < 5 ? '<span class="status-badge pass">PASS</span>' : '<span class="status-badge fail">FAIL</span>'}</p>
244
+ <p><strong>Execution Time:</strong> ${new Date().toISOString()}</p>
245
+ </div>
246
+
247
+ ${metrics.errors.size > 0 ? `
248
+ <div class="section-title">Error Breakdown</div>
249
+ <table>
250
+ <thead>
251
+ <tr>
252
+ <th>Error Type</th>
253
+ <th>Count</th>
254
+ </tr>
255
+ </thead>
256
+ <tbody>
257
+ ${errorRows}
258
+ </tbody>
259
+ </table>
260
+ ` : ""}
261
+ </div>
262
+
263
+ <div class="footer">
264
+ <p>Generated by k6-perf-reporter</p>
265
+ </div>
266
+ </div>
267
+ </body>
268
+ </html>
269
+ `;
270
+ return html;
271
+ }
272
+ generateCSVReport(metrics, testName) {
273
+ const timestamp = new Date().toISOString();
274
+ let csv = "k6 Performance Test Report\n";
275
+ csv += `Test Name,${testName}\n`;
276
+ csv += `Generated,${timestamp}\n\n`;
277
+ csv += "RESPONSE TIME METRICS\n";
278
+ csv += `Metric,Value (ms)\n`;
279
+ csv += `P50,${metrics.responseTimeP50.toFixed(2)}\n`;
280
+ csv += `P95,${metrics.responseTimeP95.toFixed(2)}\n`;
281
+ csv += `P99,${metrics.responseTimeP99.toFixed(2)}\n\n`;
282
+ csv += "THROUGHPUT & REQUESTS\n";
283
+ csv += `Metric,Value\n`;
284
+ csv += `Throughput (req/s),${metrics.throughput.toFixed(2)}\n`;
285
+ csv += `Total Requests,${metrics.totalRequests}\n`;
286
+ csv += `Successful Requests,${metrics.successfulRequests}\n`;
287
+ csv += `Failed Requests,${metrics.failedRequests}\n`;
288
+ csv += `Error Rate (%),${metrics.errorRate.toFixed(2)}\n\n`;
289
+ if (metrics.errors.size > 0) {
290
+ csv += "ERROR BREAKDOWN\n";
291
+ csv += "Error Type,Count\n";
292
+ metrics.errors.forEach((count, error) => {
293
+ csv += `"${error}",${count}\n`;
294
+ });
295
+ }
296
+ return csv;
297
+ }
298
+ generateJSONReport(metrics, testName) {
299
+ const errorObject = Object.fromEntries(metrics.errors);
300
+ const report = {
301
+ testName,
302
+ generatedAt: new Date().toISOString(),
303
+ metrics: {
304
+ responseTime: {
305
+ p50: metrics.responseTimeP50,
306
+ p95: metrics.responseTimeP95,
307
+ p99: metrics.responseTimeP99,
308
+ },
309
+ throughput: {
310
+ requestsPerSecond: metrics.throughput,
311
+ },
312
+ requests: {
313
+ total: metrics.totalRequests,
314
+ successful: metrics.successfulRequests,
315
+ failed: metrics.failedRequests,
316
+ errorRate: metrics.errorRate,
317
+ },
318
+ errors: errorObject,
319
+ },
320
+ };
321
+ return JSON.stringify(report, null, 2);
322
+ }
323
+ }
324
+ exports.ReportGenerator = ReportGenerator;
325
+ //# sourceMappingURL=reports.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reports.js","sourceRoot":"","sources":["../src/reports.ts"],"names":[],"mappings":";;;;;;AAAA,kDAA0B;AAI1B,MAAa,eAAe;IAC1B,YAAoB,YAA+B;QAA/B,iBAAY,GAAZ,YAAY,CAAmB;IAAG,CAAC;IAEvD,KAAK,CAAC,eAAe,CACnB,QAAgB,EAChB,SAAiB,EACjB,OAAe;QAEf,OAAO,CAAC,GAAG,CACT,eAAK,CAAC,IAAI,CAAC,uCAAuC,eAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,CAC1E,CAAC;QACF,OAAO,CAAC,GAAG,CAAC,eAAK,CAAC,IAAI,CAAC,oBAAoB,SAAS,OAAO,OAAO,EAAE,CAAC,CAAC,CAAC;QAEvE,IAAI,CAAC;YACH,OAAO,CAAC,GAAG,CAAC,eAAK,CAAC,IAAI,CAAC,+CAA+C,CAAC,CAAC,CAAC;YACzE,MAAM,oBAAoB,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;YACxC,MAAM,WAAW,GAAG,MAAM,IAAI,CAAC,YAAY,CAAC,0BAA0B,CACpE,QAAQ,EACR,SAAS,EACT,OAAO,CACR,CAAC;YACF,MAAM,mBAAmB,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,oBAAoB,CAAC;YAC9D,OAAO,CAAC,GAAG,CACT,eAAK,CAAC,KAAK,CACT,iCAAiC,WAAW,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,WAAW,WAAW,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,WAAW,WAAW,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,mBAAmB,KAAK,CACrK,CACF,CAAC;YAEF,OAAO,CAAC,GAAG,CAAC,eAAK,CAAC,IAAI,CAAC,wCAAwC,CAAC,CAAC,CAAC;YAClE,MAAM,cAAc,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;YAClC,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,YAAY,CAAC,eAAe,CACnD,QAAQ,EACR,SAAS,EACT,OAAO,CACR,CAAC;YACF,MAAM,aAAa,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,cAAc,CAAC;YAClD,OAAO,CAAC,GAAG,CACT,eAAK,CAAC,KAAK,CACT,6BAA6B,KAAK,CAAC,KAAK,aAAa,KAAK,CAAC,OAAO,YAAY,KAAK,CAAC,MAAM,KAAK,aAAa,KAAK,CAClH,CACF,CAAC;YAEF,OAAO,CAAC,GAAG,CAAC,eAAK,CAAC,IAAI,CAAC,qCAAqC,CAAC,CAAC,CAAC;YAC/D,MAAM,eAAe,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;YACnC,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,YAAY,CAAC,iBAAiB,CACtD,QAAQ,EACR,SAAS,EACT,OAAO,CACR,CAAC;YACF,MAAM,cAAc,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,eAAe,CAAC;YACpD,MAAM,UAAU,GAAG,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC,MAAM,CACnD,CAAC,GAAG,EAAE,KAAK,EAAE,EAAE,CAAC,GAAG,GAAG,KAAK,EAC3B,CAAC,CACF,CAAC;YACF,OAAO,CAAC,GAAG,CACT,eAAK,CAAC,KAAK,CACT,qBAAqB,MAAM,CAAC,IAAI,wBAAwB,UAAU,kBAAkB,cAAc,KAAK,CACxG,CACF,CAAC;YAEF,MAAM,WAAW,GAAG,KAAK,CAAC,KAAK;gBAC7B,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,GAAG,KAAK,CAAC,KAAK,CAAC,GAAG,GAAG;gBACrC,CAAC,CAAC,CAAC,CAAC;YACN,MAAM,SAAS,GAAG,GAAG,GAAG,WAAW,CAAC;YAEpC,6CAA6C;YAC7C,MAAM,SAAS,GAAG,IAAI,IAAI,CAAC,SAAS,CAAC,CAAC;YACtC,MAAM,OAAO,GAAG,IAAI,IAAI,CAAC,OAAO,CAAC,CAAC;YAClC,MAAM,eAAe,GACnB,CAAC,OAAO,CAAC,OAAO,EAAE,GAAG,SAAS,CAAC,OAAO,EAAE,CAAC,GAAG,IAAI,IAAI,CAAC,CAAC;YACxD,MAAM,UAAU,GAAG,KAAK,CAAC,KAAK,GAAG,eAAe,CAAC;YAEjD,OAAO,CAAC,GAAG,CACT,eAAK,CAAC,IAAI,CACR,oCAAoC,SAAS,CAAC,OAAO,CAAC,CAAC,CAAC,iBAAiB,UAAU,CAAC,OAAO,CAAC,CAAC,CAAC,QAAQ,CACvG,CACF,CAAC;YAEF,OAAO;gBACL,eAAe,EAAE,WAAW,CAAC,GAAG;gBAChC,eAAe,EAAE,WAAW,CAAC,GAAG;gBAChC,eAAe,EAAE,WAAW,CAAC,GAAG;gBAChC,UAAU;gBACV,aAAa,EAAE,KAAK,CAAC,KAAK;gBAC1B,kBAAkB,EAAE,KAAK,CAAC,OAAO;gBACjC,cAAc,EAAE,KAAK,CAAC,MAAM;gBAC5B,SAAS;gBACT,MAAM;aACP,CAAC;QACJ,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,CAAC,KAAK,CACX,eAAK,CAAC,GAAG,CAAC,6BAA6B,CAAC,EACxC,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,CAC/C,CAAC;YACF,MAAM,KAAK,CAAC;QACd,CAAC;IACH,CAAC;IAED,kBAAkB,CAAC,OAAoB,EAAE,QAAgB;QACvD,MAAM,SAAS,GAAG,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;aACnD,GAAG,CACF,CAAC,CAAC,KAAK,EAAE,KAAK,CAAC,EAAE,EAAE,CACjB,WAAW,KAAK,YAAY,KAAK,YAAY,CAChD;aACA,IAAI,CAAC,EAAE,CAAC,CAAC;QAEZ,MAAM,IAAI,GAAG;;;;;;4BAMW,QAAQ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;WAmIzB,QAAQ;uDACoC,IAAI,IAAI,EAAE,CAAC,cAAc,EAAE;;;;;;;sCAO5C,OAAO,CAAC,eAAe,CAAC,OAAO,CAAC,CAAC,CAAC;;;;sCAIlC,OAAO,CAAC,eAAe,CAAC,OAAO,CAAC,CAAC,CAAC;;;;sCAIlC,OAAO,CAAC,eAAe,CAAC,OAAO,CAAC,CAAC,CAAC;;;;sCAIlC,OAAO,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC,CAAC;;;;sCAI7B,OAAO,CAAC,aAAa;;kCAEzB,OAAO,CAAC,SAAS,GAAG,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,IAAI,OAAO,CAAC,SAAS,GAAG,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE;;sCAE5E,OAAO,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,CAAC;;;;sCAI5B,OAAO,CAAC,kBAAkB;;kCAE9B,OAAO,CAAC,cAAc,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE;;sCAEtC,OAAO,CAAC,cAAc;;;;;;yCAMnB,QAAQ;sCACX,OAAO,CAAC,SAAS,GAAG,CAAC,CAAC,CAAC,CAAC,6CAA6C,CAAC,CAAC,CAAC,6CAA6C;8CAC7G,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;;;QAG9D,OAAO,CAAC,MAAM,CAAC,IAAI,GAAG,CAAC,CAAC,CAAC,CAAC;;;;;;;;;;YAUtB,SAAS;;;OAGd,CAAC,CAAC,CAAC,EAAE;;;;;;;;;CASX,CAAC;QACE,OAAO,IAAI,CAAC;IACd,CAAC;IAED,iBAAiB,CAAC,OAAoB,EAAE,QAAgB;QACtD,MAAM,SAAS,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;QAE3C,IAAI,GAAG,GAAG,8BAA8B,CAAC;QACzC,GAAG,IAAI,aAAa,QAAQ,IAAI,CAAC;QACjC,GAAG,IAAI,aAAa,SAAS,MAAM,CAAC;QAEpC,GAAG,IAAI,yBAAyB,CAAC;QACjC,GAAG,IAAI,qBAAqB,CAAC;QAC7B,GAAG,IAAI,OAAO,OAAO,CAAC,eAAe,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC;QACrD,GAAG,IAAI,OAAO,OAAO,CAAC,eAAe,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC;QACrD,GAAG,IAAI,OAAO,OAAO,CAAC,eAAe,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC;QAEvD,GAAG,IAAI,yBAAyB,CAAC;QACjC,GAAG,IAAI,gBAAgB,CAAC;QACxB,GAAG,IAAI,sBAAsB,OAAO,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC;QAC/D,GAAG,IAAI,kBAAkB,OAAO,CAAC,aAAa,IAAI,CAAC;QACnD,GAAG,IAAI,uBAAuB,OAAO,CAAC,kBAAkB,IAAI,CAAC;QAC7D,GAAG,IAAI,mBAAmB,OAAO,CAAC,cAAc,IAAI,CAAC;QACrD,GAAG,IAAI,kBAAkB,OAAO,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC;QAE5D,IAAI,OAAO,CAAC,MAAM,CAAC,IAAI,GAAG,CAAC,EAAE,CAAC;YAC5B,GAAG,IAAI,mBAAmB,CAAC;YAC3B,GAAG,IAAI,oBAAoB,CAAC;YAC5B,OAAO,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,KAAK,EAAE,KAAK,EAAE,EAAE;gBACtC,GAAG,IAAI,IAAI,KAAK,KAAK,KAAK,IAAI,CAAC;YACjC,CAAC,CAAC,CAAC;QACL,CAAC;QAED,OAAO,GAAG,CAAC;IACb,CAAC;IAED,kBAAkB,CAAC,OAAoB,EAAE,QAAgB;QACvD,MAAM,WAAW,GAAG,MAAM,CAAC,WAAW,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;QAEvD,MAAM,MAAM,GAAG;YACb,QAAQ;YACR,WAAW,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;YACrC,OAAO,EAAE;gBACP,YAAY,EAAE;oBACZ,GAAG,EAAE,OAAO,CAAC,eAAe;oBAC5B,GAAG,EAAE,OAAO,CAAC,eAAe;oBAC5B,GAAG,EAAE,OAAO,CAAC,eAAe;iBAC7B;gBACD,UAAU,EAAE;oBACV,iBAAiB,EAAE,OAAO,CAAC,UAAU;iBACtC;gBACD,QAAQ,EAAE;oBACR,KAAK,EAAE,OAAO,CAAC,aAAa;oBAC5B,UAAU,EAAE,OAAO,CAAC,kBAAkB;oBACtC,MAAM,EAAE,OAAO,CAAC,cAAc;oBAC9B,SAAS,EAAE,OAAO,CAAC,SAAS;iBAC7B;gBACD,MAAM,EAAE,WAAW;aACpB;SACF,CAAC;QAEF,OAAO,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;IACzC,CAAC;CACF;AAvXD,0CAuXC"}
@@ -0,0 +1,113 @@
1
+ export interface ResponseTimePercentiles {
2
+ p50: number;
3
+ p95: number;
4
+ p99: number;
5
+ }
6
+ export interface RequestStats {
7
+ total: number;
8
+ success: number;
9
+ failed: number;
10
+ }
11
+ export interface VUsStats {
12
+ vusMax: number;
13
+ vusConfiguredMax: number;
14
+ }
15
+ export interface ChecksStats {
16
+ total: number;
17
+ succeeded: number;
18
+ failed: number;
19
+ successRate: number;
20
+ }
21
+ export interface DataTransferStats {
22
+ received: number;
23
+ sent: number;
24
+ receivedRate: number;
25
+ sentRate: number;
26
+ }
27
+ export interface ErrorDetail {
28
+ status: number;
29
+ url: string;
30
+ count: number;
31
+ }
32
+ export interface EndpointSummary {
33
+ url: string;
34
+ method: string;
35
+ count: number;
36
+ successful: number;
37
+ failed: number;
38
+ minResponseTime: number;
39
+ avgResponseTime: number;
40
+ p95ResponseTime: number;
41
+ p99ResponseTime: number;
42
+ maxResponseTime: number;
43
+ }
44
+ export interface ErrorEndpointSummary {
45
+ count: number;
46
+ minResponseTime: number;
47
+ avgResponseTime: number;
48
+ p95ResponseTime: number;
49
+ p99ResponseTime: number;
50
+ maxResponseTime: number;
51
+ }
52
+ export interface ErrorEndpointDetailedSummary {
53
+ url: string;
54
+ method: string;
55
+ status: number;
56
+ count: number;
57
+ minResponseTime: number;
58
+ avgResponseTime: number;
59
+ p95ResponseTime: number;
60
+ p99ResponseTime: number;
61
+ maxResponseTime: number;
62
+ }
63
+ export interface HttpPhaseStats {
64
+ avg: number;
65
+ min: number;
66
+ max: number;
67
+ p90: number;
68
+ p95: number;
69
+ }
70
+ export interface SlowestRequest {
71
+ url: string;
72
+ p95: number;
73
+ max: number;
74
+ }
75
+ export interface RpsEndpointStats {
76
+ avg: number;
77
+ max: number;
78
+ p95: number;
79
+ }
80
+ export interface TestMetrics {
81
+ responseTimeP50: number;
82
+ responseTimeP95: number;
83
+ responseTimeP99: number;
84
+ totalRequests: number;
85
+ successfulRequests: number;
86
+ failedRequests: number;
87
+ errorRate: number;
88
+ errors: Record<string, number>;
89
+ errorDetails: ErrorDetail[];
90
+ errorRequestsSummary: Record<string, ErrorEndpointSummary>;
91
+ errorRequestsDetailedSummary: ErrorEndpointDetailedSummary[];
92
+ vusMax: number;
93
+ vusConfiguredMax: number;
94
+ podCount: number;
95
+ droppedIterations: number;
96
+ slowestRequests: SlowestRequest[];
97
+ iterationDurationP50: number;
98
+ iterationDurationP95: number;
99
+ iterationDurationP99: number;
100
+ checksTotal: number;
101
+ checksSucceeded: number;
102
+ checksFailed: number;
103
+ checksSuccessRate: number;
104
+ httpPhases: Record<string, HttpPhaseStats>;
105
+ dataReceivedBytes: number;
106
+ dataSentBytes: number;
107
+ dataReceivedRate: number;
108
+ dataSentRate: number;
109
+ requestsByEndpoint: Record<string, number>;
110
+ rpsPerEndpoint: Record<string, RpsEndpointStats>;
111
+ requestsSummary: Record<string, EndpointSummary>;
112
+ }
113
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
package/dist/types.js ADDED
@@ -0,0 +1,4 @@
1
+ "use strict";
2
+ // Domain types for k6 performance metrics
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":";AAAA,0CAA0C"}
@@ -0,0 +1,2 @@
1
+ export declare function formatDuration(ms: number): string;
2
+ //# sourceMappingURL=utils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAAA,wBAAgB,cAAc,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,CAajD"}
package/dist/utils.js ADDED
@@ -0,0 +1,19 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.formatDuration = formatDuration;
4
+ function formatDuration(ms) {
5
+ const totalSeconds = Math.floor(ms / 1000);
6
+ const hours = Math.floor(totalSeconds / 3600);
7
+ const minutes = Math.floor((totalSeconds % 3600) / 60);
8
+ const seconds = totalSeconds % 60;
9
+ if (hours > 0) {
10
+ return `${hours}h ${minutes}m ${seconds}s`;
11
+ }
12
+ else if (minutes > 0) {
13
+ return `${minutes}m ${seconds}s`;
14
+ }
15
+ else {
16
+ return `${seconds}s`;
17
+ }
18
+ }
19
+ //# sourceMappingURL=utils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.js","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":";;AAAA,wCAaC;AAbD,SAAgB,cAAc,CAAC,EAAU;IACvC,MAAM,YAAY,GAAG,IAAI,CAAC,KAAK,CAAC,EAAE,GAAG,IAAI,CAAC,CAAC;IAC3C,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,GAAG,IAAI,CAAC,CAAC;IAC9C,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,YAAY,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC;IACvD,MAAM,OAAO,GAAG,YAAY,GAAG,EAAE,CAAC;IAElC,IAAI,KAAK,GAAG,CAAC,EAAE,CAAC;QACd,OAAO,GAAG,KAAK,KAAK,OAAO,KAAK,OAAO,GAAG,CAAC;IAC7C,CAAC;SAAM,IAAI,OAAO,GAAG,CAAC,EAAE,CAAC;QACvB,OAAO,GAAG,OAAO,KAAK,OAAO,GAAG,CAAC;IACnC,CAAC;SAAM,CAAC;QACN,OAAO,GAAG,OAAO,GAAG,CAAC;IACvB,CAAC;AACH,CAAC"}
package/package.json ADDED
@@ -0,0 +1,33 @@
1
+ {
2
+ "name": "k6-perf-reporter",
3
+ "version": "1.0.0",
4
+ "description": "Reporting tool for k6 performance tests with InfluxDB 2 integration",
5
+ "main": "dist/index.js",
6
+ "scripts": {
7
+ "dev": "tsx src/index.ts",
8
+ "build": "tsc",
9
+ "start": "node dist/index.js",
10
+ "report": "tsx src/cli.ts",
11
+ "report:example": "tsx src/cli.ts generate --run-id '123456790121' -st '-3h'",
12
+ "report:example:json": "tsx src/cli.ts generate --run-id '123456790121' -st '-4h' --format json",
13
+ "lint": "eslint src",
14
+ "type-check": "tsc --noEmit"
15
+ },
16
+ "dependencies": {
17
+ "@influxdata/influxdb-client": "^1.33.2",
18
+ "chalk": "^5.3.0",
19
+ "commander": "^11.1.0",
20
+ "table": "^6.8.1"
21
+ },
22
+ "devDependencies": {
23
+ "@types/node": "^20.10.6",
24
+ "@typescript-eslint/eslint-plugin": "^8.58.1",
25
+ "@typescript-eslint/parser": "^8.58.1",
26
+ "eslint": "^8.56.0",
27
+ "tsx": "^4.7.0",
28
+ "typescript": "^5.3.3"
29
+ },
30
+ "publishConfig": {
31
+ "access": "public"
32
+ }
33
+ }
package/src/cli.ts ADDED
@@ -0,0 +1,47 @@
1
+ import { program } from "commander";
2
+ import { Config } from "./config";
3
+ import { DataCollector } from "./data-collector";
4
+ import { JsonReporter, CliReporter } from "./reporters";
5
+
6
+ function main(): void {
7
+ program
8
+ .name("k6-reporter")
9
+ .description("Generate CLI reports from k6 tests stored in InfluxDB")
10
+ .version("1.0.0");
11
+
12
+ program
13
+ .command("generate")
14
+ .description("Generate performance test report")
15
+ .requiredOption("--run-id <id>", "k6 test run ID")
16
+ .option("-st, --start-time <time>", "Start time in ISO 8601 format or relative like '-1h'")
17
+ .option("-et, --end-time <time>", "End time in ISO 8601 format (defaults to now)")
18
+ .option("-c, --config <path>", "Path to config file", ".config.json")
19
+ .option("-f, --format <format>", "Output format: 'json' or 'cli'", "cli")
20
+ .option("-o, --output <path>", "Output file path (for json format)")
21
+ .action(async (options) => {
22
+ try {
23
+ const config = Config.getInstance(options.config).getConfig();
24
+ const collector = new DataCollector(config);
25
+ const report = await collector.collect(
26
+ options.runId,
27
+ options.startTime || "-1h",
28
+ options.endTime || "now()"
29
+ );
30
+
31
+ if (options.format === "json") {
32
+ const jsonReporter = new JsonReporter();
33
+ jsonReporter.report(report, options.output);
34
+ } else {
35
+ const cliReporter = new CliReporter();
36
+ cliReporter.report(report);
37
+ }
38
+ } catch (error) {
39
+ console.error("Error:", error instanceof Error ? error.message : error);
40
+ process.exit(1);
41
+ }
42
+ });
43
+
44
+ program.parse();
45
+ }
46
+
47
+ main();
package/src/config.ts ADDED
@@ -0,0 +1,31 @@
1
+ import fs from "fs";
2
+ import path from "path";
3
+
4
+ export interface InfluxConfig {
5
+ url: string;
6
+ token: string;
7
+ org: string;
8
+ bucket: string;
9
+ }
10
+
11
+ export class Config {
12
+ private static instance: Config;
13
+ private config: InfluxConfig;
14
+
15
+ private constructor(configPath: string = ".config.json") {
16
+ const fullPath = path.resolve(configPath);
17
+ const data = JSON.parse(fs.readFileSync(fullPath, "utf-8"));
18
+ this.config = data.influx;
19
+ }
20
+
21
+ static getInstance(configPath?: string): Config {
22
+ if (!Config.instance) {
23
+ Config.instance = new Config(configPath);
24
+ }
25
+ return Config.instance;
26
+ }
27
+
28
+ getConfig(): InfluxConfig {
29
+ return this.config;
30
+ }
31
+ }
@@ -0,0 +1,66 @@
1
+ import { InfluxDataExtractor } from "./influx-data-extractor";
2
+ import { InfluxConfig } from "./config";
3
+
4
+ export interface ReporterResponse {
5
+ runId: string;
6
+ startTime: string;
7
+ endTime: string;
8
+ timestamp: string;
9
+ data: unknown;
10
+ }
11
+
12
+ export class DataCollector {
13
+ private extractor: InfluxDataExtractor;
14
+
15
+ constructor(config: InfluxConfig) {
16
+ this.extractor = new InfluxDataExtractor(config);
17
+ }
18
+
19
+ async collect(
20
+ runId: string,
21
+ startTime: string = "-1h",
22
+ endTime: string = "now()",
23
+ data: unknown = {}
24
+ ): Promise<ReporterResponse> {
25
+ const httpReqs = await this.extractor.extractHttpReqs(runId, startTime, endTime);
26
+ const vus = await this.extractor.extractVus(runId, startTime, endTime);
27
+ const vusMax = await this.extractor.extractVusMax(runId, startTime, endTime);
28
+ const iterations = await this.extractor.extractIterations(runId, startTime, endTime);
29
+ const duration = await this.extractor.calculateTestDuration(runId, startTime, endTime);
30
+ const checks = await this.extractor.extractChecks(runId, startTime, endTime);
31
+ const httpReqFailed = await this.extractor.extractHttpReqFailed(runId, startTime, endTime);
32
+ const httpReqDuration = await this.extractor.extractHttpReqDuration(runId, startTime, endTime);
33
+ const iterationDuration = await this.extractor.extractIterationDuration(runId, startTime, endTime);
34
+ const errorResponses = await this.extractor.extractErrorResponses(runId, startTime, endTime);
35
+ const topSlowUrls = await this.extractor.extractTopSlowUrls(runId, startTime, endTime);
36
+ const errorRequests = await this.extractor.extractErrorRequests(runId, startTime, endTime);
37
+ const successRequests = await this.extractor.extractSuccessRequests(runId, startTime, endTime);
38
+ const errorResponsesText = await this.extractor.extractErrorResponsesText(runId, startTime, endTime);
39
+
40
+ const reportData = {
41
+ ...(typeof data === "object" && data !== null ? data : {}),
42
+ httpReqs,
43
+ vus,
44
+ vusMax,
45
+ iterations,
46
+ duration,
47
+ checks,
48
+ httpReqFailed,
49
+ httpReqDuration,
50
+ iterationDuration,
51
+ errorResponses,
52
+ topSlowUrls,
53
+ errorRequests,
54
+ successRequests,
55
+ errorResponsesText,
56
+ };
57
+
58
+ return {
59
+ runId,
60
+ startTime,
61
+ endTime,
62
+ timestamp: new Date().toISOString(),
63
+ data: reportData,
64
+ };
65
+ }
66
+ }