k6-perf-reporter 1.6.0 → 1.6.2
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 +33 -4
- package/dist/cli.js +13 -6
- package/dist/cli.js.map +1 -1
- package/dist/reporters/index.d.ts +1 -0
- package/dist/reporters/index.d.ts.map +1 -1
- package/dist/reporters/index.js +3 -1
- package/dist/reporters/index.js.map +1 -1
- package/dist/reporters/markdown-reporter.d.ts +11 -0
- package/dist/reporters/markdown-reporter.d.ts.map +1 -0
- package/dist/reporters/markdown-reporter.js +200 -0
- package/dist/reporters/markdown-reporter.js.map +1 -0
- package/dist/reporters/slack-reporter.d.ts +3 -0
- package/dist/reporters/slack-reporter.d.ts.map +1 -1
- package/dist/reporters/slack-reporter.js +85 -18
- package/dist/reporters/slack-reporter.js.map +1 -1
- package/package.json +1 -1
- package/src/cli.ts +13 -7
- package/src/reporters/index.ts +1 -0
- package/src/reporters/markdown-reporter.ts +230 -0
- package/src/reporters/slack-reporter.ts +94 -18
package/README.md
CHANGED
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
# k6-perf-reporter
|
|
2
2
|
|
|
3
|
-
A comprehensive reporting tool for k6 performance tests with InfluxDB 2 integration. Generates beautiful CLI, JSON, and Slack reports with key performance metrics.
|
|
3
|
+
A comprehensive reporting tool for k6 performance tests with InfluxDB 2 integration. Generates beautiful CLI, JSON, Markdown, and Slack reports with key performance metrics.
|
|
4
4
|
|
|
5
5
|
## Features
|
|
6
6
|
|
|
7
|
-
- **Multiple Report Formats**: CLI output, JSON, and Slack integration
|
|
7
|
+
- **Multiple Report Formats**: CLI output, JSON, Markdown, and Slack integration
|
|
8
8
|
- **InfluxDB 2 Integration**: Query test metrics directly from InfluxDB
|
|
9
9
|
- **Key Metrics**: RPS, HTTP requests, checks, error rates, latencies, and more
|
|
10
10
|
- **Real-time Slack Notifications**: Send formatted test reports directly to Slack channels
|
|
11
|
+
- **Markdown Reports**: Generate exportable markdown files for documentation and archiving
|
|
11
12
|
- **CLI Tool**: Command-line interface for automated report generation
|
|
12
13
|
- **Library Support**: Use as a TypeScript/JavaScript library in your own tools
|
|
13
14
|
|
|
@@ -138,6 +139,30 @@ Slack message includes:
|
|
|
138
139
|
- Error requests
|
|
139
140
|
- Error responses with error types
|
|
140
141
|
|
|
142
|
+
#### Markdown Report
|
|
143
|
+
|
|
144
|
+
Generate a markdown file for documentation, wikis, or archiving:
|
|
145
|
+
|
|
146
|
+
```bash
|
|
147
|
+
npx tsx src/cli.ts generate \
|
|
148
|
+
--run-id 123456790121 \
|
|
149
|
+
--start-time "-1h" \
|
|
150
|
+
--format markdown \
|
|
151
|
+
--output report.md
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
Markdown report includes:
|
|
155
|
+
- Formatted header with run ID, start/end times
|
|
156
|
+
- Summary with pass/fail status and key metrics table
|
|
157
|
+
- Metrics section with all performance data
|
|
158
|
+
- Tables for:
|
|
159
|
+
- Top slowest URLs
|
|
160
|
+
- RPS per URL
|
|
161
|
+
- Error requests
|
|
162
|
+
- Error responses with error types
|
|
163
|
+
|
|
164
|
+
See [example markdown report](examples/report.example.md) for output format.
|
|
165
|
+
|
|
141
166
|
### Command Options
|
|
142
167
|
|
|
143
168
|
```
|
|
@@ -145,8 +170,8 @@ Slack message includes:
|
|
|
145
170
|
-st, --start-time <time> Start time (relative: -1h, -30m, or ISO 8601)
|
|
146
171
|
-et, --end-time <time> End time (ISO 8601 format, defaults to now)
|
|
147
172
|
-c, --config <path> Path to config file (default: .config.json)
|
|
148
|
-
-f, --format <format> Output format: 'json', 'cli', or 'slack' (default: cli)
|
|
149
|
-
-o, --output <path> Output file path (for json
|
|
173
|
+
-f, --format <format> Output format: 'json', 'cli', 'markdown', or 'slack' (default: cli)
|
|
174
|
+
-o, --output <path> Output file path (for json and markdown formats)
|
|
150
175
|
```
|
|
151
176
|
|
|
152
177
|
### Time Format Examples
|
|
@@ -248,6 +273,9 @@ npx tsx src/cli.ts generate --run-id 123456 -st -1h --format cli
|
|
|
248
273
|
# Save as JSON
|
|
249
274
|
npx tsx src/cli.ts generate --run-id 123456 -st -1h --format json -o report.json
|
|
250
275
|
|
|
276
|
+
# Save as Markdown
|
|
277
|
+
npx tsx src/cli.ts generate --run-id 123456 -st -1h --format markdown -o report.md
|
|
278
|
+
|
|
251
279
|
# Send to Slack
|
|
252
280
|
npx tsx src/cli.ts generate --run-id 123456 -st -1h --format slack
|
|
253
281
|
```
|
|
@@ -319,6 +347,7 @@ src/
|
|
|
319
347
|
├── reporters/
|
|
320
348
|
│ ├── cli-reporter.ts # CLI table formatting
|
|
321
349
|
│ ├── json-reporter.ts # JSON export
|
|
350
|
+
│ ├── markdown-reporter.ts # Markdown export
|
|
322
351
|
│ ├── slack-reporter.ts # Slack integration
|
|
323
352
|
│ └── index.ts # Reporter exports
|
|
324
353
|
├── cli.ts # Command-line interface
|
package/dist/cli.js
CHANGED
|
@@ -17,7 +17,7 @@ function main() {
|
|
|
17
17
|
.option("-st, --start-time <time>", "Start time in ISO 8601 format or relative like '-1h'")
|
|
18
18
|
.option("-et, --end-time <time>", "End time in ISO 8601 format (defaults to now)")
|
|
19
19
|
.option("-c, --config <path>", "Path to config file", ".config.json")
|
|
20
|
-
.option("-f, --format <format>", "Output format: 'json', 'cli', or 'slack'", "cli")
|
|
20
|
+
.option("-f, --format <format>", "Output format: 'json', 'cli', 'markdown', or 'slack'", "cli")
|
|
21
21
|
.option("-o, --output <path>", "Output file path (for json format)")
|
|
22
22
|
.action(async (options) => {
|
|
23
23
|
try {
|
|
@@ -28,6 +28,10 @@ function main() {
|
|
|
28
28
|
const jsonReporter = new reporters_1.JsonReporter();
|
|
29
29
|
jsonReporter.report(report, options.output);
|
|
30
30
|
}
|
|
31
|
+
else if (options.format === "markdown") {
|
|
32
|
+
const markdownReporter = new reporters_1.MarkdownReporter();
|
|
33
|
+
markdownReporter.report(report, options.output);
|
|
34
|
+
}
|
|
31
35
|
else if (options.format === "slack") {
|
|
32
36
|
const slackConfig = config_1.Config.getInstance(options.config).getSlackConfig();
|
|
33
37
|
if (!slackConfig) {
|
|
@@ -69,8 +73,8 @@ OPTIONS:
|
|
|
69
73
|
-st, --start-time Start time (relative: -1h, -30m, or ISO 8601)
|
|
70
74
|
-et, --end-time End time (ISO 8601 format, defaults to now)
|
|
71
75
|
-c, --config Path to config file (default: .config.json)
|
|
72
|
-
-f, --format Output format: 'json', 'cli', or 'slack' (default: cli)
|
|
73
|
-
-o, --output Output file path (for json
|
|
76
|
+
-f, --format Output format: 'json', 'cli', 'markdown', or 'slack' (default: cli)
|
|
77
|
+
-o, --output Output file path (for json and markdown formats)
|
|
74
78
|
-h, --help Show command help
|
|
75
79
|
-V, --version Show version
|
|
76
80
|
|
|
@@ -88,13 +92,16 @@ EXAMPLES:
|
|
|
88
92
|
4. Save JSON report to file:
|
|
89
93
|
k6-reporter generate --run-id 123456790121 --format json -o report.json
|
|
90
94
|
|
|
91
|
-
5.
|
|
95
|
+
5. Generate Markdown report and save to file:
|
|
96
|
+
k6-reporter generate --run-id 123456790121 --format markdown -o report.md
|
|
97
|
+
|
|
98
|
+
6. Send report to Slack:
|
|
92
99
|
SLACK_TOKEN=xoxb-... k6-reporter generate --run-id 123456790121 --format slack
|
|
93
100
|
|
|
94
|
-
|
|
101
|
+
7. Use custom config file:
|
|
95
102
|
k6-reporter generate --run-id 123456790121 -c /path/to/config.json
|
|
96
103
|
|
|
97
|
-
|
|
104
|
+
8. Get help for generate command:
|
|
98
105
|
k6-reporter generate --help
|
|
99
106
|
|
|
100
107
|
TIME FORMAT:
|
package/dist/cli.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";;;AAEA,yCAAoC;AACpC,qCAAkC;AAClC,qDAAiD;AACjD,
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";;;AAEA,yCAAoC;AACpC,qCAAkC;AAClC,qDAAiD;AACjD,2CAAyF;AAEzF,SAAS,IAAI;IACX,mBAAO;SACJ,IAAI,CAAC,aAAa,CAAC;SACnB,WAAW,CAAC,uDAAuD,CAAC;SACpE,OAAO,CAAC,OAAO,CAAC,CAAC;IAEpB,mBAAO;SACJ,OAAO,CAAC,UAAU,CAAC;SACnB,WAAW,CAAC,kCAAkC,CAAC;SAC/C,cAAc,CAAC,eAAe,EAAE,gBAAgB,CAAC;SACjD,MAAM,CAAC,0BAA0B,EAAE,sDAAsD,CAAC;SAC1F,MAAM,CAAC,wBAAwB,EAAE,+CAA+C,CAAC;SACjF,MAAM,CAAC,qBAAqB,EAAE,qBAAqB,EAAE,cAAc,CAAC;SACpE,MAAM,CAAC,uBAAuB,EAAE,sDAAsD,EAAE,KAAK,CAAC;SAC9F,MAAM,CAAC,qBAAqB,EAAE,oCAAoC,CAAC;SACnE,MAAM,CAAC,KAAK,EAAE,OAAO,EAAE,EAAE;QACxB,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,eAAM,CAAC,WAAW,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,eAAe,EAAE,CAAC;YACpE,MAAM,SAAS,GAAG,IAAI,8BAAa,CAAC,MAAM,CAAC,CAAC;YAC5C,MAAM,MAAM,GAAG,MAAM,SAAS,CAAC,OAAO,CACpC,OAAO,CAAC,KAAK,EACb,OAAO,CAAC,SAAS,IAAI,KAAK,EAC1B,OAAO,CAAC,OAAO,IAAI,OAAO,CAC3B,CAAC;YAEF,IAAI,OAAO,CAAC,MAAM,KAAK,MAAM,EAAE,CAAC;gBAC9B,MAAM,YAAY,GAAG,IAAI,wBAAY,EAAE,CAAC;gBACxC,YAAY,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC;YAC9C,CAAC;iBAAM,IAAI,OAAO,CAAC,MAAM,KAAK,UAAU,EAAE,CAAC;gBACzC,MAAM,gBAAgB,GAAG,IAAI,4BAAgB,EAAE,CAAC;gBAChD,gBAAgB,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC;YAClD,CAAC;iBAAM,IAAI,OAAO,CAAC,MAAM,KAAK,OAAO,EAAE,CAAC;gBACtC,MAAM,WAAW,GAAG,eAAM,CAAC,WAAW,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,cAAc,EAAE,CAAC;gBACxE,IAAI,CAAC,WAAW,EAAE,CAAC;oBACjB,MAAM,IAAI,KAAK,CAAC,+FAA+F,CAAC,CAAC;gBACnH,CAAC;gBACD,MAAM,aAAa,GAAG,IAAI,yBAAa,CAAC,WAAW,CAAC,KAAK,EAAE,WAAW,CAAC,OAAO,CAAC,CAAC;gBAChF,MAAM,aAAa,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;gBACnC,OAAO,CAAC,GAAG,CAAC,sBAAsB,CAAC,CAAC;YACtC,CAAC;iBAAM,CAAC;gBACN,MAAM,WAAW,GAAG,IAAI,uBAAW,EAAE,CAAC;gBACtC,WAAW,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;YAC7B,CAAC;QACH,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,CAAC,KAAK,CAAC,QAAQ,EAAE,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;YACxE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;IACH,CAAC,CAAC,CAAC;IAEL,mBAAO;SACJ,OAAO,CAAC,MAAM,CAAC;SACf,WAAW,CAAC,wBAAwB,CAAC;SACrC,MAAM,CAAC,GAAG,EAAE;QACX,OAAO,CAAC,GAAG,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAsEX,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEL,mBAAO,CAAC,KAAK,EAAE,CAAC;AAClB,CAAC;AAED,IAAI,EAAE,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/reporters/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAC/C,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAC7C,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/reporters/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAC/C,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAC7C,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACjD,OAAO,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC"}
|
package/dist/reporters/index.js
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.SlackReporter = exports.CliReporter = exports.JsonReporter = void 0;
|
|
3
|
+
exports.MarkdownReporter = exports.SlackReporter = exports.CliReporter = exports.JsonReporter = void 0;
|
|
4
4
|
var json_reporter_1 = require("./json-reporter");
|
|
5
5
|
Object.defineProperty(exports, "JsonReporter", { enumerable: true, get: function () { return json_reporter_1.JsonReporter; } });
|
|
6
6
|
var cli_reporter_1 = require("./cli-reporter");
|
|
7
7
|
Object.defineProperty(exports, "CliReporter", { enumerable: true, get: function () { return cli_reporter_1.CliReporter; } });
|
|
8
8
|
var slack_reporter_1 = require("./slack-reporter");
|
|
9
9
|
Object.defineProperty(exports, "SlackReporter", { enumerable: true, get: function () { return slack_reporter_1.SlackReporter; } });
|
|
10
|
+
var markdown_reporter_1 = require("./markdown-reporter");
|
|
11
|
+
Object.defineProperty(exports, "MarkdownReporter", { enumerable: true, get: function () { return markdown_reporter_1.MarkdownReporter; } });
|
|
10
12
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/reporters/index.ts"],"names":[],"mappings":";;;AAAA,iDAA+C;AAAtC,6GAAA,YAAY,OAAA;AACrB,+CAA6C;AAApC,2GAAA,WAAW,OAAA;AACpB,mDAAiD;AAAxC,+GAAA,aAAa,OAAA"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/reporters/index.ts"],"names":[],"mappings":";;;AAAA,iDAA+C;AAAtC,6GAAA,YAAY,OAAA;AACrB,+CAA6C;AAApC,2GAAA,WAAW,OAAA;AACpB,mDAAiD;AAAxC,+GAAA,aAAa,OAAA;AACtB,yDAAuD;AAA9C,qHAAA,gBAAgB,OAAA"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { ReporterResponse } from "../data-collector";
|
|
2
|
+
export declare class MarkdownReporter {
|
|
3
|
+
report(data: ReporterResponse, outputPath?: string): void;
|
|
4
|
+
private generateMarkdown;
|
|
5
|
+
private generateSummary;
|
|
6
|
+
private generateMetrics;
|
|
7
|
+
private generateTables;
|
|
8
|
+
private tableToMarkdown;
|
|
9
|
+
private formatDuration;
|
|
10
|
+
}
|
|
11
|
+
//# sourceMappingURL=markdown-reporter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"markdown-reporter.d.ts","sourceRoot":"","sources":["../../src/reporters/markdown-reporter.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAGrD,qBAAa,gBAAgB;IAC3B,MAAM,CAAC,IAAI,EAAE,gBAAgB,EAAE,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI;IAWzD,OAAO,CAAC,gBAAgB;IAsBxB,OAAO,CAAC,eAAe;IA4BvB,OAAO,CAAC,eAAe;IAyCvB,OAAO,CAAC,cAAc;IAkGtB,OAAO,CAAC,eAAe;IAevB,OAAO,CAAC,cAAc;CASvB"}
|
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.MarkdownReporter = void 0;
|
|
4
|
+
const fs_1 = require("fs");
|
|
5
|
+
class MarkdownReporter {
|
|
6
|
+
report(data, outputPath) {
|
|
7
|
+
const markdown = this.generateMarkdown(data);
|
|
8
|
+
if (outputPath) {
|
|
9
|
+
(0, fs_1.writeFileSync)(outputPath, markdown);
|
|
10
|
+
console.log(`Report saved to ${outputPath}`);
|
|
11
|
+
}
|
|
12
|
+
else {
|
|
13
|
+
console.log(markdown);
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
generateMarkdown(data) {
|
|
17
|
+
const reportData = data.data;
|
|
18
|
+
let markdown = "";
|
|
19
|
+
// Header
|
|
20
|
+
markdown += `# k6 Performance Test Report\n\n`;
|
|
21
|
+
markdown += `- **Run ID:** ${data.runId}\n`;
|
|
22
|
+
markdown += `- **Start:** ${data.startTime}\n`;
|
|
23
|
+
markdown += `- **End:** ${data.endTime}\n\n`;
|
|
24
|
+
// Summary section
|
|
25
|
+
markdown += this.generateSummary(reportData);
|
|
26
|
+
// Main metrics
|
|
27
|
+
markdown += this.generateMetrics(reportData);
|
|
28
|
+
// Tables
|
|
29
|
+
markdown += this.generateTables(reportData);
|
|
30
|
+
return markdown;
|
|
31
|
+
}
|
|
32
|
+
generateSummary(reportData) {
|
|
33
|
+
let summary = "## Summary\n\n";
|
|
34
|
+
let errorPercent = 0;
|
|
35
|
+
let failedChecks = 0;
|
|
36
|
+
if (reportData.httpReqFailed) {
|
|
37
|
+
const failed = reportData.httpReqFailed;
|
|
38
|
+
errorPercent = typeof failed.failureRate === "number" ? failed.failureRate : 0;
|
|
39
|
+
}
|
|
40
|
+
if (reportData.checks) {
|
|
41
|
+
const checks = reportData.checks;
|
|
42
|
+
failedChecks = typeof checks.fails === "number" ? checks.fails : 0;
|
|
43
|
+
}
|
|
44
|
+
const isSuccess = errorPercent < 1 && failedChecks === 0;
|
|
45
|
+
const status = isSuccess ? "✓ PASS" : "✗ FAIL";
|
|
46
|
+
summary += `**Status:** ${status}\n\n`;
|
|
47
|
+
summary += `| Metric | Value |\n`;
|
|
48
|
+
summary += `|--------|-------|\n`;
|
|
49
|
+
summary += `| Error Rate | ${errorPercent.toFixed(2)}% |\n`;
|
|
50
|
+
summary += `| Failed Checks | ${failedChecks} |\n\n`;
|
|
51
|
+
return summary;
|
|
52
|
+
}
|
|
53
|
+
generateMetrics(reportData) {
|
|
54
|
+
let metrics = "## Metrics\n\n";
|
|
55
|
+
if (reportData.checks) {
|
|
56
|
+
const checks = reportData.checks;
|
|
57
|
+
const passRate = typeof checks.passRate === "number" ? checks.passRate : 0;
|
|
58
|
+
metrics += `- **Checks:** ${passRate.toFixed(2)}% (${checks.passes} ✓${checks.fails ? `, ${checks.fails} ✗` : ""})\n`;
|
|
59
|
+
}
|
|
60
|
+
if (reportData.rpsAggregated) {
|
|
61
|
+
const rpsAgg = reportData.rpsAggregated;
|
|
62
|
+
const avg = typeof rpsAgg.avg === "number" ? rpsAgg.avg : 0;
|
|
63
|
+
const p95 = typeof rpsAgg.p95 === "number" ? rpsAgg.p95 : 0;
|
|
64
|
+
const max = typeof rpsAgg.max === "number" ? rpsAgg.max : 0;
|
|
65
|
+
metrics += `- **RPS:** avg=${avg.toFixed(2)}, p(95)=${p95.toFixed(2)}, max=${max.toFixed(2)}\n`;
|
|
66
|
+
}
|
|
67
|
+
if (reportData.httpReqs) {
|
|
68
|
+
const httpReqs = reportData.httpReqs;
|
|
69
|
+
metrics += `- **HTTP Requests:** ${httpReqs.total} (${httpReqs.rate.toFixed(6)}/s)\n`;
|
|
70
|
+
}
|
|
71
|
+
if (reportData.iterations) {
|
|
72
|
+
const iterations = reportData.iterations;
|
|
73
|
+
metrics += `- **Iterations:** ${iterations.total} (${iterations.rate.toFixed(6)}/s)\n`;
|
|
74
|
+
}
|
|
75
|
+
if (reportData.httpReqDuration) {
|
|
76
|
+
const duration = reportData.httpReqDuration;
|
|
77
|
+
metrics += `- **HTTP Duration:** avg=${this.formatDuration(duration.avg || 0)}, p(95)=${this.formatDuration(duration.p95 || 0)}\n`;
|
|
78
|
+
}
|
|
79
|
+
if (reportData.vus) {
|
|
80
|
+
const vus = reportData.vus;
|
|
81
|
+
metrics += `- **VUs:** ${vus.current} (min=${vus.min}, max=${vus.max})\n`;
|
|
82
|
+
}
|
|
83
|
+
metrics += "\n";
|
|
84
|
+
return metrics;
|
|
85
|
+
}
|
|
86
|
+
generateTables(reportData) {
|
|
87
|
+
let tables = "";
|
|
88
|
+
if (reportData.topSlowUrls) {
|
|
89
|
+
const topSlowUrls = reportData.topSlowUrls;
|
|
90
|
+
const urls = topSlowUrls.urls;
|
|
91
|
+
if (urls && urls.length > 0) {
|
|
92
|
+
tables += "## Top 10 Slowest URLs\n\n";
|
|
93
|
+
const tableData = [
|
|
94
|
+
["#", "Method", "URL", "p(95)"],
|
|
95
|
+
...urls.map((u, i) => [String(i + 1), u.method, u.url, this.formatDuration(u.p95Duration)]),
|
|
96
|
+
];
|
|
97
|
+
tables += this.tableToMarkdown(tableData) + "\n\n";
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
if (reportData.rpsPerUrl) {
|
|
101
|
+
const rpsPerUrl = reportData.rpsPerUrl;
|
|
102
|
+
const urls = rpsPerUrl.urls;
|
|
103
|
+
if (urls && urls.length > 0) {
|
|
104
|
+
tables += "## RPS per URL\n\n";
|
|
105
|
+
const tableData = [
|
|
106
|
+
["#", "Method", "URL", "Count", "avg", "p(95)", "max"],
|
|
107
|
+
...urls.map((u, i) => [String(i + 1), u.method, u.url, String(u.count), u.rps.avg.toFixed(2), u.rps.p95.toFixed(2), u.rps.max.toFixed(2)]),
|
|
108
|
+
];
|
|
109
|
+
tables += this.tableToMarkdown(tableData) + "\n\n";
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
if (reportData.successRequests) {
|
|
113
|
+
const successRequests = reportData.successRequests;
|
|
114
|
+
const requests = successRequests.requests;
|
|
115
|
+
if (requests && requests.length > 0) {
|
|
116
|
+
tables += "## Top Successful Requests\n\n";
|
|
117
|
+
const tableData = [
|
|
118
|
+
["#", "Method", "URL", "Status", "Count", "Min", "Avg", "p(95)"],
|
|
119
|
+
...requests.map((r, i) => [String(i + 1), r.method, r.url, String(r.status), String(r.count), this.formatDuration(r.min), this.formatDuration(r.avg), this.formatDuration(r.p95)]),
|
|
120
|
+
];
|
|
121
|
+
tables += this.tableToMarkdown(tableData) + "\n\n";
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
if (reportData.errorRequests) {
|
|
125
|
+
const errorRequests = reportData.errorRequests;
|
|
126
|
+
const errors = errorRequests.errors;
|
|
127
|
+
if (errors && errors.length > 0) {
|
|
128
|
+
tables += "## Top Error Requests\n\n";
|
|
129
|
+
const tableData = [
|
|
130
|
+
["#", "Method", "URL", "Code", "Count"],
|
|
131
|
+
...errors.map((e, i) => [String(i + 1), e.method, e.url, String(e.status), String(e.count)]),
|
|
132
|
+
];
|
|
133
|
+
tables += this.tableToMarkdown(tableData) + "\n\n";
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
if (reportData.errorResponsesText) {
|
|
137
|
+
const errorResponsesText = reportData.errorResponsesText;
|
|
138
|
+
const responses = errorResponsesText.responses;
|
|
139
|
+
if (responses && responses.length > 0) {
|
|
140
|
+
const groupedErrors = new Map();
|
|
141
|
+
responses.forEach((r) => {
|
|
142
|
+
const key = `${r.method}|${r.url}|${r.status}|${r.error}`;
|
|
143
|
+
if (groupedErrors.has(key)) {
|
|
144
|
+
const entry = groupedErrors.get(key);
|
|
145
|
+
entry.count++;
|
|
146
|
+
}
|
|
147
|
+
else {
|
|
148
|
+
groupedErrors.set(key, {
|
|
149
|
+
method: r.method,
|
|
150
|
+
url: r.url,
|
|
151
|
+
status: r.status,
|
|
152
|
+
error: r.error || "",
|
|
153
|
+
count: 1,
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
});
|
|
157
|
+
tables += "## Error Responses\n\n";
|
|
158
|
+
const tableData = [
|
|
159
|
+
["#", "Method", "URL", "Status", "Error", "Count"],
|
|
160
|
+
...Array.from(groupedErrors.values()).map((r, i) => {
|
|
161
|
+
let url = r.url;
|
|
162
|
+
try {
|
|
163
|
+
const urlObj = new URL(url);
|
|
164
|
+
url = urlObj.pathname;
|
|
165
|
+
}
|
|
166
|
+
catch {
|
|
167
|
+
// If not a full URL, use as-is
|
|
168
|
+
}
|
|
169
|
+
return [String(i + 1), r.method, url, String(r.status), r.error, String(r.count)];
|
|
170
|
+
}),
|
|
171
|
+
];
|
|
172
|
+
tables += this.tableToMarkdown(tableData) + "\n\n";
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
return tables;
|
|
176
|
+
}
|
|
177
|
+
tableToMarkdown(tableData) {
|
|
178
|
+
if (tableData.length === 0) {
|
|
179
|
+
return "";
|
|
180
|
+
}
|
|
181
|
+
const [headers, ...rows] = tableData;
|
|
182
|
+
let markdown = "| " + headers.join(" | ") + " |\n";
|
|
183
|
+
markdown += "|" + headers.map(() => " --- ").join("|") + "|\n";
|
|
184
|
+
rows.forEach((row) => {
|
|
185
|
+
markdown += "| " + row.join(" | ") + " |\n";
|
|
186
|
+
});
|
|
187
|
+
return markdown;
|
|
188
|
+
}
|
|
189
|
+
formatDuration(ms) {
|
|
190
|
+
if (ms < 1) {
|
|
191
|
+
return `${(ms * 1000).toFixed(2)}µs`;
|
|
192
|
+
}
|
|
193
|
+
if (ms < 1000) {
|
|
194
|
+
return `${ms.toFixed(2)}ms`;
|
|
195
|
+
}
|
|
196
|
+
return `${(ms / 1000).toFixed(2)}s`;
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
exports.MarkdownReporter = MarkdownReporter;
|
|
200
|
+
//# sourceMappingURL=markdown-reporter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"markdown-reporter.js","sourceRoot":"","sources":["../../src/reporters/markdown-reporter.ts"],"names":[],"mappings":"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"}
|
|
@@ -8,7 +8,10 @@ export declare class SlackReporter {
|
|
|
8
8
|
private generateSummary;
|
|
9
9
|
private generateMetrics;
|
|
10
10
|
private generateTables;
|
|
11
|
+
private formatTable;
|
|
11
12
|
private formatDuration;
|
|
13
|
+
private sendMessages;
|
|
14
|
+
private splitIntoMessages;
|
|
12
15
|
private sendMessage;
|
|
13
16
|
}
|
|
14
17
|
//# sourceMappingURL=slack-reporter.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"slack-reporter.d.ts","sourceRoot":"","sources":["../../src/reporters/slack-reporter.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAGrD,qBAAa,aAAa;IACxB,OAAO,CAAC,MAAM,CAAY;IAC1B,OAAO,CAAC,OAAO,CAAS;gBAEZ,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM;IAQpC,MAAM,CAAC,IAAI,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC;IAKnD,OAAO,CAAC,gBAAgB;
|
|
1
|
+
{"version":3,"file":"slack-reporter.d.ts","sourceRoot":"","sources":["../../src/reporters/slack-reporter.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAGrD,qBAAa,aAAa;IACxB,OAAO,CAAC,MAAM,CAAY;IAC1B,OAAO,CAAC,OAAO,CAAS;gBAEZ,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM;IAQpC,MAAM,CAAC,IAAI,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC;IAKnD,OAAO,CAAC,gBAAgB;IAsBxB,OAAO,CAAC,eAAe;IA2BvB,OAAO,CAAC,eAAe;IAyCvB,OAAO,CAAC,cAAc;IAkGtB,OAAO,CAAC,WAAW;IAkCnB,OAAO,CAAC,cAAc;YAUR,YAAY;IAS1B,OAAO,CAAC,iBAAiB;YAuBX,WAAW;CAmB1B"}
|
|
@@ -13,15 +13,16 @@ class SlackReporter {
|
|
|
13
13
|
}
|
|
14
14
|
async report(data) {
|
|
15
15
|
const markdown = this.generateMarkdown(data);
|
|
16
|
-
await this.
|
|
16
|
+
await this.sendMessages(markdown);
|
|
17
17
|
}
|
|
18
18
|
generateMarkdown(data) {
|
|
19
19
|
const reportData = data.data;
|
|
20
20
|
let markdown = "";
|
|
21
21
|
// Header
|
|
22
|
-
markdown +=
|
|
23
|
-
markdown +=
|
|
24
|
-
markdown +=
|
|
22
|
+
markdown += `*k6 Performance Test Report*\n`;
|
|
23
|
+
markdown += `• *Run ID:* ${data.runId}\n`;
|
|
24
|
+
markdown += `• *Start:* ${data.startTime}\n`;
|
|
25
|
+
markdown += `• *End:* ${data.endTime}\n\n`;
|
|
25
26
|
// Summary section
|
|
26
27
|
markdown += this.generateSummary(reportData);
|
|
27
28
|
// Main metrics
|
|
@@ -31,7 +32,7 @@ class SlackReporter {
|
|
|
31
32
|
return markdown;
|
|
32
33
|
}
|
|
33
34
|
generateSummary(reportData) {
|
|
34
|
-
let summary = "";
|
|
35
|
+
let summary = "*Summary*\n";
|
|
35
36
|
let errorPercent = 0;
|
|
36
37
|
let failedChecks = 0;
|
|
37
38
|
if (reportData.httpReqFailed) {
|
|
@@ -45,7 +46,7 @@ class SlackReporter {
|
|
|
45
46
|
const isSuccess = errorPercent < 1 && failedChecks === 0;
|
|
46
47
|
const status = isSuccess ? "✓ PASS" : "✗ FAIL";
|
|
47
48
|
const statusEmoji = isSuccess ? "✅" : "❌";
|
|
48
|
-
summary += `${statusEmoji} *${status}*\n`;
|
|
49
|
+
summary += `${statusEmoji} *${status}*\n\n`;
|
|
49
50
|
summary += `• Error Rate: ${errorPercent.toFixed(2)}%\n`;
|
|
50
51
|
summary += `• Failed Checks: ${failedChecks}\n\n`;
|
|
51
52
|
return summary;
|
|
@@ -89,39 +90,48 @@ class SlackReporter {
|
|
|
89
90
|
const topSlowUrls = reportData.topSlowUrls;
|
|
90
91
|
const urls = topSlowUrls.urls;
|
|
91
92
|
if (urls && urls.length > 0) {
|
|
92
|
-
tables += "*Top 10 Slowest URLs
|
|
93
|
+
tables += "*Top 10 Slowest URLs*\n";
|
|
93
94
|
const tableData = [
|
|
94
95
|
["#", "Method", "URL", "p(95)"],
|
|
95
96
|
...urls.map((u, i) => [String(i + 1), u.method, u.url, this.formatDuration(u.p95Duration)]),
|
|
96
97
|
];
|
|
97
|
-
tables +=
|
|
98
|
-
tables += "```\n\n";
|
|
98
|
+
tables += "```\n" + this.formatTable(tableData) + "```\n\n";
|
|
99
99
|
}
|
|
100
100
|
}
|
|
101
101
|
if (reportData.rpsPerUrl) {
|
|
102
102
|
const rpsPerUrl = reportData.rpsPerUrl;
|
|
103
103
|
const urls = rpsPerUrl.urls;
|
|
104
104
|
if (urls && urls.length > 0) {
|
|
105
|
-
tables += "*RPS per URL
|
|
105
|
+
tables += "*RPS per URL*\n";
|
|
106
106
|
const tableData = [
|
|
107
107
|
["#", "Method", "URL", "Count", "avg", "p(95)", "max"],
|
|
108
108
|
...urls.map((u, i) => [String(i + 1), u.method, u.url, String(u.count), u.rps.avg.toFixed(2), u.rps.p95.toFixed(2), u.rps.max.toFixed(2)]),
|
|
109
109
|
];
|
|
110
|
-
tables +=
|
|
111
|
-
|
|
110
|
+
tables += "```\n" + this.formatTable(tableData) + "```\n\n";
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
if (reportData.successRequests) {
|
|
114
|
+
const successRequests = reportData.successRequests;
|
|
115
|
+
const requests = successRequests.requests;
|
|
116
|
+
if (requests && requests.length > 0) {
|
|
117
|
+
tables += "*Top Successful Requests*\n";
|
|
118
|
+
const tableData = [
|
|
119
|
+
["#", "Method", "URL", "Status", "Count", "Min", "Avg", "p(95)"],
|
|
120
|
+
...requests.map((r, i) => [String(i + 1), r.method, r.url, String(r.status), String(r.count), this.formatDuration(r.min), this.formatDuration(r.avg), this.formatDuration(r.p95)]),
|
|
121
|
+
];
|
|
122
|
+
tables += "```\n" + this.formatTable(tableData) + "```\n\n";
|
|
112
123
|
}
|
|
113
124
|
}
|
|
114
125
|
if (reportData.errorRequests) {
|
|
115
126
|
const errorRequests = reportData.errorRequests;
|
|
116
127
|
const errors = errorRequests.errors;
|
|
117
128
|
if (errors && errors.length > 0) {
|
|
118
|
-
tables += "*Top Error Requests
|
|
129
|
+
tables += "*Top Error Requests*\n";
|
|
119
130
|
const tableData = [
|
|
120
131
|
["#", "Method", "URL", "Code", "Count"],
|
|
121
132
|
...errors.map((e, i) => [String(i + 1), e.method, e.url, String(e.status), String(e.count)]),
|
|
122
133
|
];
|
|
123
|
-
tables +=
|
|
124
|
-
tables += "```\n\n";
|
|
134
|
+
tables += "```\n" + this.formatTable(tableData) + "```\n\n";
|
|
125
135
|
}
|
|
126
136
|
}
|
|
127
137
|
if (reportData.errorResponsesText) {
|
|
@@ -145,7 +155,7 @@ class SlackReporter {
|
|
|
145
155
|
});
|
|
146
156
|
}
|
|
147
157
|
});
|
|
148
|
-
tables += "*Error Responses
|
|
158
|
+
tables += "*Error Responses*\n";
|
|
149
159
|
const tableData = [
|
|
150
160
|
["#", "Method", "URL", "Status", "Error", "Count"],
|
|
151
161
|
...Array.from(groupedErrors.values()).map((r, i) => {
|
|
@@ -160,12 +170,42 @@ class SlackReporter {
|
|
|
160
170
|
return [String(i + 1), r.method, url, String(r.status), r.error, String(r.count)];
|
|
161
171
|
}),
|
|
162
172
|
];
|
|
163
|
-
tables +=
|
|
164
|
-
tables += "```\n\n";
|
|
173
|
+
tables += "```\n" + this.formatTable(tableData) + "```\n\n";
|
|
165
174
|
}
|
|
166
175
|
}
|
|
167
176
|
return tables;
|
|
168
177
|
}
|
|
178
|
+
formatTable(tableData) {
|
|
179
|
+
if (tableData.length === 0) {
|
|
180
|
+
return "";
|
|
181
|
+
}
|
|
182
|
+
const columnCount = tableData[0].length;
|
|
183
|
+
const columnConfig = {};
|
|
184
|
+
for (let i = 0; i < columnCount; i++) {
|
|
185
|
+
columnConfig[i] = { alignment: "left" };
|
|
186
|
+
}
|
|
187
|
+
return (0, table_1.table)(tableData, {
|
|
188
|
+
border: {
|
|
189
|
+
topBody: "─",
|
|
190
|
+
topJoin: "┬",
|
|
191
|
+
topLeft: "┌",
|
|
192
|
+
topRight: "┐",
|
|
193
|
+
bottomBody: "─",
|
|
194
|
+
bottomJoin: "┴",
|
|
195
|
+
bottomLeft: "└",
|
|
196
|
+
bottomRight: "┘",
|
|
197
|
+
bodyLeft: "│",
|
|
198
|
+
bodyRight: "│",
|
|
199
|
+
bodyJoin: "│",
|
|
200
|
+
joinBody: "─",
|
|
201
|
+
joinLeft: "├",
|
|
202
|
+
joinRight: "┤",
|
|
203
|
+
joinJoin: "┼",
|
|
204
|
+
},
|
|
205
|
+
drawHorizontalLine: (index) => index === 1,
|
|
206
|
+
columns: columnConfig,
|
|
207
|
+
});
|
|
208
|
+
}
|
|
169
209
|
formatDuration(ms) {
|
|
170
210
|
if (ms < 1) {
|
|
171
211
|
return `${(ms * 1000).toFixed(2)}µs`;
|
|
@@ -175,6 +215,33 @@ class SlackReporter {
|
|
|
175
215
|
}
|
|
176
216
|
return `${(ms / 1000).toFixed(2)}s`;
|
|
177
217
|
}
|
|
218
|
+
async sendMessages(markdown) {
|
|
219
|
+
const MAX_BLOCK_LENGTH = 3000;
|
|
220
|
+
const messages = this.splitIntoMessages(markdown, MAX_BLOCK_LENGTH);
|
|
221
|
+
for (const message of messages) {
|
|
222
|
+
await this.sendMessage(message);
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
splitIntoMessages(text, maxLength) {
|
|
226
|
+
const messages = [];
|
|
227
|
+
const sections = text.split(/(\n\n)/);
|
|
228
|
+
let currentMessage = "";
|
|
229
|
+
for (const section of sections) {
|
|
230
|
+
if ((currentMessage + section).length <= maxLength) {
|
|
231
|
+
currentMessage += section;
|
|
232
|
+
}
|
|
233
|
+
else {
|
|
234
|
+
if (currentMessage) {
|
|
235
|
+
messages.push(currentMessage);
|
|
236
|
+
}
|
|
237
|
+
currentMessage = section;
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
if (currentMessage) {
|
|
241
|
+
messages.push(currentMessage);
|
|
242
|
+
}
|
|
243
|
+
return messages;
|
|
244
|
+
}
|
|
178
245
|
async sendMessage(markdown) {
|
|
179
246
|
try {
|
|
180
247
|
await this.client.chat.postMessage({
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"slack-reporter.js","sourceRoot":"","sources":["../../src/reporters/slack-reporter.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"slack-reporter.js","sourceRoot":"","sources":["../../src/reporters/slack-reporter.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
package/src/cli.ts
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
import { program } from "commander";
|
|
4
4
|
import { Config } from "./config";
|
|
5
5
|
import { DataCollector } from "./data-collector";
|
|
6
|
-
import { JsonReporter, CliReporter, SlackReporter } from "./reporters";
|
|
6
|
+
import { JsonReporter, CliReporter, SlackReporter, MarkdownReporter } from "./reporters";
|
|
7
7
|
|
|
8
8
|
function main(): void {
|
|
9
9
|
program
|
|
@@ -18,7 +18,7 @@ function main(): void {
|
|
|
18
18
|
.option("-st, --start-time <time>", "Start time in ISO 8601 format or relative like '-1h'")
|
|
19
19
|
.option("-et, --end-time <time>", "End time in ISO 8601 format (defaults to now)")
|
|
20
20
|
.option("-c, --config <path>", "Path to config file", ".config.json")
|
|
21
|
-
.option("-f, --format <format>", "Output format: 'json', 'cli', or 'slack'", "cli")
|
|
21
|
+
.option("-f, --format <format>", "Output format: 'json', 'cli', 'markdown', or 'slack'", "cli")
|
|
22
22
|
.option("-o, --output <path>", "Output file path (for json format)")
|
|
23
23
|
.action(async (options) => {
|
|
24
24
|
try {
|
|
@@ -33,6 +33,9 @@ function main(): void {
|
|
|
33
33
|
if (options.format === "json") {
|
|
34
34
|
const jsonReporter = new JsonReporter();
|
|
35
35
|
jsonReporter.report(report, options.output);
|
|
36
|
+
} else if (options.format === "markdown") {
|
|
37
|
+
const markdownReporter = new MarkdownReporter();
|
|
38
|
+
markdownReporter.report(report, options.output);
|
|
36
39
|
} else if (options.format === "slack") {
|
|
37
40
|
const slackConfig = Config.getInstance(options.config).getSlackConfig();
|
|
38
41
|
if (!slackConfig) {
|
|
@@ -73,8 +76,8 @@ OPTIONS:
|
|
|
73
76
|
-st, --start-time Start time (relative: -1h, -30m, or ISO 8601)
|
|
74
77
|
-et, --end-time End time (ISO 8601 format, defaults to now)
|
|
75
78
|
-c, --config Path to config file (default: .config.json)
|
|
76
|
-
-f, --format Output format: 'json', 'cli', or 'slack' (default: cli)
|
|
77
|
-
-o, --output Output file path (for json
|
|
79
|
+
-f, --format Output format: 'json', 'cli', 'markdown', or 'slack' (default: cli)
|
|
80
|
+
-o, --output Output file path (for json and markdown formats)
|
|
78
81
|
-h, --help Show command help
|
|
79
82
|
-V, --version Show version
|
|
80
83
|
|
|
@@ -92,13 +95,16 @@ EXAMPLES:
|
|
|
92
95
|
4. Save JSON report to file:
|
|
93
96
|
k6-reporter generate --run-id 123456790121 --format json -o report.json
|
|
94
97
|
|
|
95
|
-
5.
|
|
98
|
+
5. Generate Markdown report and save to file:
|
|
99
|
+
k6-reporter generate --run-id 123456790121 --format markdown -o report.md
|
|
100
|
+
|
|
101
|
+
6. Send report to Slack:
|
|
96
102
|
SLACK_TOKEN=xoxb-... k6-reporter generate --run-id 123456790121 --format slack
|
|
97
103
|
|
|
98
|
-
|
|
104
|
+
7. Use custom config file:
|
|
99
105
|
k6-reporter generate --run-id 123456790121 -c /path/to/config.json
|
|
100
106
|
|
|
101
|
-
|
|
107
|
+
8. Get help for generate command:
|
|
102
108
|
k6-reporter generate --help
|
|
103
109
|
|
|
104
110
|
TIME FORMAT:
|
package/src/reporters/index.ts
CHANGED
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
import { writeFileSync } from "fs";
|
|
2
|
+
import { ReporterResponse } from "../data-collector";
|
|
3
|
+
import { table } from "table";
|
|
4
|
+
|
|
5
|
+
export class MarkdownReporter {
|
|
6
|
+
report(data: ReporterResponse, outputPath?: string): void {
|
|
7
|
+
const markdown = this.generateMarkdown(data);
|
|
8
|
+
|
|
9
|
+
if (outputPath) {
|
|
10
|
+
writeFileSync(outputPath, markdown);
|
|
11
|
+
console.log(`Report saved to ${outputPath}`);
|
|
12
|
+
} else {
|
|
13
|
+
console.log(markdown);
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
private generateMarkdown(data: ReporterResponse): string {
|
|
18
|
+
const reportData = data.data as Record<string, unknown>;
|
|
19
|
+
let markdown = "";
|
|
20
|
+
|
|
21
|
+
// Header
|
|
22
|
+
markdown += `# k6 Performance Test Report\n\n`;
|
|
23
|
+
markdown += `- **Run ID:** ${data.runId}\n`;
|
|
24
|
+
markdown += `- **Start:** ${data.startTime}\n`;
|
|
25
|
+
markdown += `- **End:** ${data.endTime}\n\n`;
|
|
26
|
+
|
|
27
|
+
// Summary section
|
|
28
|
+
markdown += this.generateSummary(reportData);
|
|
29
|
+
|
|
30
|
+
// Main metrics
|
|
31
|
+
markdown += this.generateMetrics(reportData);
|
|
32
|
+
|
|
33
|
+
// Tables
|
|
34
|
+
markdown += this.generateTables(reportData);
|
|
35
|
+
|
|
36
|
+
return markdown;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
private generateSummary(reportData: Record<string, unknown>): string {
|
|
40
|
+
let summary = "## Summary\n\n";
|
|
41
|
+
|
|
42
|
+
let errorPercent = 0;
|
|
43
|
+
let failedChecks = 0;
|
|
44
|
+
|
|
45
|
+
if (reportData.httpReqFailed) {
|
|
46
|
+
const failed = reportData.httpReqFailed as Record<string, number>;
|
|
47
|
+
errorPercent = typeof failed.failureRate === "number" ? failed.failureRate : 0;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
if (reportData.checks) {
|
|
51
|
+
const checks = reportData.checks as Record<string, number>;
|
|
52
|
+
failedChecks = typeof checks.fails === "number" ? checks.fails : 0;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const isSuccess = errorPercent < 1 && failedChecks === 0;
|
|
56
|
+
const status = isSuccess ? "✓ PASS" : "✗ FAIL";
|
|
57
|
+
|
|
58
|
+
summary += `**Status:** ${status}\n\n`;
|
|
59
|
+
summary += `| Metric | Value |\n`;
|
|
60
|
+
summary += `|--------|-------|\n`;
|
|
61
|
+
summary += `| Error Rate | ${errorPercent.toFixed(2)}% |\n`;
|
|
62
|
+
summary += `| Failed Checks | ${failedChecks} |\n\n`;
|
|
63
|
+
|
|
64
|
+
return summary;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
private generateMetrics(reportData: Record<string, unknown>): string {
|
|
68
|
+
let metrics = "## Metrics\n\n";
|
|
69
|
+
|
|
70
|
+
if (reportData.checks) {
|
|
71
|
+
const checks = reportData.checks as Record<string, number>;
|
|
72
|
+
const passRate = typeof checks.passRate === "number" ? checks.passRate : 0;
|
|
73
|
+
metrics += `- **Checks:** ${passRate.toFixed(2)}% (${checks.passes} ✓${checks.fails ? `, ${checks.fails} ✗` : ""})\n`;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
if (reportData.rpsAggregated) {
|
|
77
|
+
const rpsAgg = reportData.rpsAggregated as Record<string, unknown>;
|
|
78
|
+
const avg = typeof rpsAgg.avg === "number" ? rpsAgg.avg : 0;
|
|
79
|
+
const p95 = typeof rpsAgg.p95 === "number" ? rpsAgg.p95 : 0;
|
|
80
|
+
const max = typeof rpsAgg.max === "number" ? rpsAgg.max : 0;
|
|
81
|
+
metrics += `- **RPS:** avg=${avg.toFixed(2)}, p(95)=${p95.toFixed(2)}, max=${max.toFixed(2)}\n`;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
if (reportData.httpReqs) {
|
|
85
|
+
const httpReqs = reportData.httpReqs as Record<string, number>;
|
|
86
|
+
metrics += `- **HTTP Requests:** ${httpReqs.total} (${httpReqs.rate.toFixed(6)}/s)\n`;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
if (reportData.iterations) {
|
|
90
|
+
const iterations = reportData.iterations as Record<string, number>;
|
|
91
|
+
metrics += `- **Iterations:** ${iterations.total} (${iterations.rate.toFixed(6)}/s)\n`;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
if (reportData.httpReqDuration) {
|
|
95
|
+
const duration = reportData.httpReqDuration as Record<string, number>;
|
|
96
|
+
metrics += `- **HTTP Duration:** avg=${this.formatDuration(duration.avg || 0)}, p(95)=${this.formatDuration(duration.p95 || 0)}\n`;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
if (reportData.vus) {
|
|
100
|
+
const vus = reportData.vus as Record<string, number>;
|
|
101
|
+
metrics += `- **VUs:** ${vus.current} (min=${vus.min}, max=${vus.max})\n`;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
metrics += "\n";
|
|
105
|
+
return metrics;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
private generateTables(reportData: Record<string, unknown>): string {
|
|
109
|
+
let tables = "";
|
|
110
|
+
|
|
111
|
+
if (reportData.topSlowUrls) {
|
|
112
|
+
const topSlowUrls = reportData.topSlowUrls as Record<string, unknown>;
|
|
113
|
+
const urls = topSlowUrls.urls as Array<{ method: string; url: string; p95Duration: number }>;
|
|
114
|
+
if (urls && urls.length > 0) {
|
|
115
|
+
tables += "## Top 10 Slowest URLs\n\n";
|
|
116
|
+
const tableData = [
|
|
117
|
+
["#", "Method", "URL", "p(95)"],
|
|
118
|
+
...urls.map((u, i) => [String(i + 1), u.method, u.url, this.formatDuration(u.p95Duration)]),
|
|
119
|
+
];
|
|
120
|
+
tables += this.tableToMarkdown(tableData) + "\n\n";
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
if (reportData.rpsPerUrl) {
|
|
125
|
+
const rpsPerUrl = reportData.rpsPerUrl as Record<string, unknown>;
|
|
126
|
+
const urls = rpsPerUrl.urls as Array<{ method: string; url: string; count: number; rps: { avg: number; p95: number; max: number } }>;
|
|
127
|
+
if (urls && urls.length > 0) {
|
|
128
|
+
tables += "## RPS per URL\n\n";
|
|
129
|
+
const tableData = [
|
|
130
|
+
["#", "Method", "URL", "Count", "avg", "p(95)", "max"],
|
|
131
|
+
...urls.map((u, i) => [String(i + 1), u.method, u.url, String(u.count), u.rps.avg.toFixed(2), u.rps.p95.toFixed(2), u.rps.max.toFixed(2)]),
|
|
132
|
+
];
|
|
133
|
+
tables += this.tableToMarkdown(tableData) + "\n\n";
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
if (reportData.successRequests) {
|
|
138
|
+
const successRequests = reportData.successRequests as Record<string, unknown>;
|
|
139
|
+
const requests = successRequests.requests as Array<{ method: string; url: string; status: number; count: number; min: number; avg: number; p95: number }>;
|
|
140
|
+
if (requests && requests.length > 0) {
|
|
141
|
+
tables += "## Top Successful Requests\n\n";
|
|
142
|
+
const tableData = [
|
|
143
|
+
["#", "Method", "URL", "Status", "Count", "Min", "Avg", "p(95)"],
|
|
144
|
+
...requests.map((r, i) => [String(i + 1), r.method, r.url, String(r.status), String(r.count), this.formatDuration(r.min), this.formatDuration(r.avg), this.formatDuration(r.p95)]),
|
|
145
|
+
];
|
|
146
|
+
tables += this.tableToMarkdown(tableData) + "\n\n";
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
if (reportData.errorRequests) {
|
|
151
|
+
const errorRequests = reportData.errorRequests as Record<string, unknown>;
|
|
152
|
+
const errors = errorRequests.errors as Array<{ method: string; url: string; status: number; count: number }>;
|
|
153
|
+
if (errors && errors.length > 0) {
|
|
154
|
+
tables += "## Top Error Requests\n\n";
|
|
155
|
+
const tableData = [
|
|
156
|
+
["#", "Method", "URL", "Code", "Count"],
|
|
157
|
+
...errors.map((e, i) => [String(i + 1), e.method, e.url, String(e.status), String(e.count)]),
|
|
158
|
+
];
|
|
159
|
+
tables += this.tableToMarkdown(tableData) + "\n\n";
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
if (reportData.errorResponsesText) {
|
|
164
|
+
const errorResponsesText = reportData.errorResponsesText as Record<string, unknown>;
|
|
165
|
+
const responses = errorResponsesText.responses as Array<{ url: string; method: string; status: number; error: string }>;
|
|
166
|
+
if (responses && responses.length > 0) {
|
|
167
|
+
const groupedErrors = new Map<string, { method: string; url: string; status: number; error: string; count: number }>();
|
|
168
|
+
|
|
169
|
+
responses.forEach((r) => {
|
|
170
|
+
const key = `${r.method}|${r.url}|${r.status}|${r.error}`;
|
|
171
|
+
if (groupedErrors.has(key)) {
|
|
172
|
+
const entry = groupedErrors.get(key)!;
|
|
173
|
+
entry.count++;
|
|
174
|
+
} else {
|
|
175
|
+
groupedErrors.set(key, {
|
|
176
|
+
method: r.method,
|
|
177
|
+
url: r.url,
|
|
178
|
+
status: r.status,
|
|
179
|
+
error: r.error || "",
|
|
180
|
+
count: 1,
|
|
181
|
+
});
|
|
182
|
+
}
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
tables += "## Error Responses\n\n";
|
|
186
|
+
const tableData = [
|
|
187
|
+
["#", "Method", "URL", "Status", "Error", "Count"],
|
|
188
|
+
...Array.from(groupedErrors.values()).map((r, i) => {
|
|
189
|
+
let url = r.url;
|
|
190
|
+
try {
|
|
191
|
+
const urlObj = new URL(url);
|
|
192
|
+
url = urlObj.pathname;
|
|
193
|
+
} catch {
|
|
194
|
+
// If not a full URL, use as-is
|
|
195
|
+
}
|
|
196
|
+
return [String(i + 1), r.method, url, String(r.status), r.error, String(r.count)];
|
|
197
|
+
}),
|
|
198
|
+
];
|
|
199
|
+
tables += this.tableToMarkdown(tableData) + "\n\n";
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
return tables;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
private tableToMarkdown(tableData: string[][]): string {
|
|
207
|
+
if (tableData.length === 0) {
|
|
208
|
+
return "";
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
const [headers, ...rows] = tableData;
|
|
212
|
+
let markdown = "| " + headers.join(" | ") + " |\n";
|
|
213
|
+
markdown += "|" + headers.map(() => " --- ").join("|") + "|\n";
|
|
214
|
+
rows.forEach((row) => {
|
|
215
|
+
markdown += "| " + row.join(" | ") + " |\n";
|
|
216
|
+
});
|
|
217
|
+
|
|
218
|
+
return markdown;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
private formatDuration(ms: number): string {
|
|
222
|
+
if (ms < 1) {
|
|
223
|
+
return `${(ms * 1000).toFixed(2)}µs`;
|
|
224
|
+
}
|
|
225
|
+
if (ms < 1000) {
|
|
226
|
+
return `${ms.toFixed(2)}ms`;
|
|
227
|
+
}
|
|
228
|
+
return `${(ms / 1000).toFixed(2)}s`;
|
|
229
|
+
}
|
|
230
|
+
}
|
|
@@ -16,7 +16,7 @@ export class SlackReporter {
|
|
|
16
16
|
|
|
17
17
|
async report(data: ReporterResponse): Promise<void> {
|
|
18
18
|
const markdown = this.generateMarkdown(data);
|
|
19
|
-
await this.
|
|
19
|
+
await this.sendMessages(markdown);
|
|
20
20
|
}
|
|
21
21
|
|
|
22
22
|
private generateMarkdown(data: ReporterResponse): string {
|
|
@@ -24,9 +24,10 @@ export class SlackReporter {
|
|
|
24
24
|
let markdown = "";
|
|
25
25
|
|
|
26
26
|
// Header
|
|
27
|
-
markdown +=
|
|
28
|
-
markdown +=
|
|
29
|
-
markdown +=
|
|
27
|
+
markdown += `*k6 Performance Test Report*\n`;
|
|
28
|
+
markdown += `• *Run ID:* ${data.runId}\n`;
|
|
29
|
+
markdown += `• *Start:* ${data.startTime}\n`;
|
|
30
|
+
markdown += `• *End:* ${data.endTime}\n\n`;
|
|
30
31
|
|
|
31
32
|
// Summary section
|
|
32
33
|
markdown += this.generateSummary(reportData);
|
|
@@ -41,7 +42,7 @@ export class SlackReporter {
|
|
|
41
42
|
}
|
|
42
43
|
|
|
43
44
|
private generateSummary(reportData: Record<string, unknown>): string {
|
|
44
|
-
let summary = "";
|
|
45
|
+
let summary = "*Summary*\n";
|
|
45
46
|
|
|
46
47
|
let errorPercent = 0;
|
|
47
48
|
let failedChecks = 0;
|
|
@@ -60,7 +61,7 @@ export class SlackReporter {
|
|
|
60
61
|
const status = isSuccess ? "✓ PASS" : "✗ FAIL";
|
|
61
62
|
const statusEmoji = isSuccess ? "✅" : "❌";
|
|
62
63
|
|
|
63
|
-
summary += `${statusEmoji} *${status}*\n`;
|
|
64
|
+
summary += `${statusEmoji} *${status}*\n\n`;
|
|
64
65
|
summary += `• Error Rate: ${errorPercent.toFixed(2)}%\n`;
|
|
65
66
|
summary += `• Failed Checks: ${failedChecks}\n\n`;
|
|
66
67
|
|
|
@@ -115,13 +116,12 @@ export class SlackReporter {
|
|
|
115
116
|
const topSlowUrls = reportData.topSlowUrls as Record<string, unknown>;
|
|
116
117
|
const urls = topSlowUrls.urls as Array<{ method: string; url: string; p95Duration: number }>;
|
|
117
118
|
if (urls && urls.length > 0) {
|
|
118
|
-
tables += "*Top 10 Slowest URLs
|
|
119
|
+
tables += "*Top 10 Slowest URLs*\n";
|
|
119
120
|
const tableData = [
|
|
120
121
|
["#", "Method", "URL", "p(95)"],
|
|
121
122
|
...urls.map((u, i) => [String(i + 1), u.method, u.url, this.formatDuration(u.p95Duration)]),
|
|
122
123
|
];
|
|
123
|
-
tables +=
|
|
124
|
-
tables += "```\n\n";
|
|
124
|
+
tables += "```\n" + this.formatTable(tableData) + "```\n\n";
|
|
125
125
|
}
|
|
126
126
|
}
|
|
127
127
|
|
|
@@ -129,13 +129,25 @@ export class SlackReporter {
|
|
|
129
129
|
const rpsPerUrl = reportData.rpsPerUrl as Record<string, unknown>;
|
|
130
130
|
const urls = rpsPerUrl.urls as Array<{ method: string; url: string; count: number; rps: { avg: number; p95: number; max: number } }>;
|
|
131
131
|
if (urls && urls.length > 0) {
|
|
132
|
-
tables += "*RPS per URL
|
|
132
|
+
tables += "*RPS per URL*\n";
|
|
133
133
|
const tableData = [
|
|
134
134
|
["#", "Method", "URL", "Count", "avg", "p(95)", "max"],
|
|
135
135
|
...urls.map((u, i) => [String(i + 1), u.method, u.url, String(u.count), u.rps.avg.toFixed(2), u.rps.p95.toFixed(2), u.rps.max.toFixed(2)]),
|
|
136
136
|
];
|
|
137
|
-
tables +=
|
|
138
|
-
|
|
137
|
+
tables += "```\n" + this.formatTable(tableData) + "```\n\n";
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
if (reportData.successRequests) {
|
|
142
|
+
const successRequests = reportData.successRequests as Record<string, unknown>;
|
|
143
|
+
const requests = successRequests.requests as Array<{ method: string; url: string; status: number; count: number; min: number; avg: number; p95: number }>;
|
|
144
|
+
if (requests && requests.length > 0) {
|
|
145
|
+
tables += "*Top Successful Requests*\n";
|
|
146
|
+
const tableData = [
|
|
147
|
+
["#", "Method", "URL", "Status", "Count", "Min", "Avg", "p(95)"],
|
|
148
|
+
...requests.map((r, i) => [String(i + 1), r.method, r.url, String(r.status), String(r.count), this.formatDuration(r.min), this.formatDuration(r.avg), this.formatDuration(r.p95)]),
|
|
149
|
+
];
|
|
150
|
+
tables += "```\n" + this.formatTable(tableData) + "```\n\n";
|
|
139
151
|
}
|
|
140
152
|
}
|
|
141
153
|
|
|
@@ -143,13 +155,12 @@ export class SlackReporter {
|
|
|
143
155
|
const errorRequests = reportData.errorRequests as Record<string, unknown>;
|
|
144
156
|
const errors = errorRequests.errors as Array<{ method: string; url: string; status: number; count: number }>;
|
|
145
157
|
if (errors && errors.length > 0) {
|
|
146
|
-
tables += "*Top Error Requests
|
|
158
|
+
tables += "*Top Error Requests*\n";
|
|
147
159
|
const tableData = [
|
|
148
160
|
["#", "Method", "URL", "Code", "Count"],
|
|
149
161
|
...errors.map((e, i) => [String(i + 1), e.method, e.url, String(e.status), String(e.count)]),
|
|
150
162
|
];
|
|
151
|
-
tables +=
|
|
152
|
-
tables += "```\n\n";
|
|
163
|
+
tables += "```\n" + this.formatTable(tableData) + "```\n\n";
|
|
153
164
|
}
|
|
154
165
|
}
|
|
155
166
|
|
|
@@ -175,7 +186,7 @@ export class SlackReporter {
|
|
|
175
186
|
}
|
|
176
187
|
});
|
|
177
188
|
|
|
178
|
-
tables += "*Error Responses
|
|
189
|
+
tables += "*Error Responses*\n";
|
|
179
190
|
const tableData = [
|
|
180
191
|
["#", "Method", "URL", "Status", "Error", "Count"],
|
|
181
192
|
...Array.from(groupedErrors.values()).map((r, i) => {
|
|
@@ -189,14 +200,47 @@ export class SlackReporter {
|
|
|
189
200
|
return [String(i + 1), r.method, url, String(r.status), r.error, String(r.count)];
|
|
190
201
|
}),
|
|
191
202
|
];
|
|
192
|
-
tables +=
|
|
193
|
-
tables += "```\n\n";
|
|
203
|
+
tables += "```\n" + this.formatTable(tableData) + "```\n\n";
|
|
194
204
|
}
|
|
195
205
|
}
|
|
196
206
|
|
|
197
207
|
return tables;
|
|
198
208
|
}
|
|
199
209
|
|
|
210
|
+
private formatTable(tableData: string[][]): string {
|
|
211
|
+
if (tableData.length === 0) {
|
|
212
|
+
return "";
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
const columnCount = tableData[0].length;
|
|
216
|
+
const columnConfig: Record<number, { alignment: "left" | "right" | "center" }> = {};
|
|
217
|
+
for (let i = 0; i < columnCount; i++) {
|
|
218
|
+
columnConfig[i] = { alignment: "left" };
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
return table(tableData, {
|
|
222
|
+
border: {
|
|
223
|
+
topBody: "─",
|
|
224
|
+
topJoin: "┬",
|
|
225
|
+
topLeft: "┌",
|
|
226
|
+
topRight: "┐",
|
|
227
|
+
bottomBody: "─",
|
|
228
|
+
bottomJoin: "┴",
|
|
229
|
+
bottomLeft: "└",
|
|
230
|
+
bottomRight: "┘",
|
|
231
|
+
bodyLeft: "│",
|
|
232
|
+
bodyRight: "│",
|
|
233
|
+
bodyJoin: "│",
|
|
234
|
+
joinBody: "─",
|
|
235
|
+
joinLeft: "├",
|
|
236
|
+
joinRight: "┤",
|
|
237
|
+
joinJoin: "┼",
|
|
238
|
+
},
|
|
239
|
+
drawHorizontalLine: (index) => index === 1,
|
|
240
|
+
columns: columnConfig,
|
|
241
|
+
});
|
|
242
|
+
}
|
|
243
|
+
|
|
200
244
|
private formatDuration(ms: number): string {
|
|
201
245
|
if (ms < 1) {
|
|
202
246
|
return `${(ms * 1000).toFixed(2)}µs`;
|
|
@@ -207,6 +251,38 @@ export class SlackReporter {
|
|
|
207
251
|
return `${(ms / 1000).toFixed(2)}s`;
|
|
208
252
|
}
|
|
209
253
|
|
|
254
|
+
private async sendMessages(markdown: string): Promise<void> {
|
|
255
|
+
const MAX_BLOCK_LENGTH = 3000;
|
|
256
|
+
const messages = this.splitIntoMessages(markdown, MAX_BLOCK_LENGTH);
|
|
257
|
+
|
|
258
|
+
for (const message of messages) {
|
|
259
|
+
await this.sendMessage(message);
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
private splitIntoMessages(text: string, maxLength: number): string[] {
|
|
264
|
+
const messages: string[] = [];
|
|
265
|
+
const sections = text.split(/(\n\n)/);
|
|
266
|
+
let currentMessage = "";
|
|
267
|
+
|
|
268
|
+
for (const section of sections) {
|
|
269
|
+
if ((currentMessage + section).length <= maxLength) {
|
|
270
|
+
currentMessage += section;
|
|
271
|
+
} else {
|
|
272
|
+
if (currentMessage) {
|
|
273
|
+
messages.push(currentMessage);
|
|
274
|
+
}
|
|
275
|
+
currentMessage = section;
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
if (currentMessage) {
|
|
280
|
+
messages.push(currentMessage);
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
return messages;
|
|
284
|
+
}
|
|
285
|
+
|
|
210
286
|
private async sendMessage(markdown: string): Promise<void> {
|
|
211
287
|
try {
|
|
212
288
|
await this.client.chat.postMessage({
|