k6-perf-reporter 1.6.6 → 1.7.1

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/.claude/settings.local.json +18 -0
  2. package/.config.example.json +3 -0
  3. package/dist/cache.d.ts +11 -0
  4. package/dist/cache.d.ts.map +1 -0
  5. package/dist/cache.js +61 -0
  6. package/dist/cache.js.map +1 -0
  7. package/dist/cli.js +89 -28
  8. package/dist/cli.js.map +1 -1
  9. package/dist/config.d.ts +12 -3
  10. package/dist/config.d.ts.map +1 -1
  11. package/dist/config.js +33 -8
  12. package/dist/config.js.map +1 -1
  13. package/dist/data-collector.d.ts +7 -10
  14. package/dist/data-collector.d.ts.map +1 -1
  15. package/dist/data-collector.js +68 -58
  16. package/dist/data-collector.js.map +1 -1
  17. package/dist/datasources/datasource.d.ts +13 -0
  18. package/dist/datasources/datasource.d.ts.map +1 -0
  19. package/dist/datasources/datasource.js +3 -0
  20. package/dist/datasources/datasource.js.map +1 -0
  21. package/dist/datasources/factory.d.ts +4 -0
  22. package/dist/datasources/factory.d.ts.map +1 -0
  23. package/dist/datasources/factory.js +19 -0
  24. package/dist/datasources/factory.js.map +1 -0
  25. package/dist/datasources/index.d.ts +4 -0
  26. package/dist/datasources/index.d.ts.map +1 -0
  27. package/dist/datasources/index.js +9 -0
  28. package/dist/datasources/index.js.map +1 -0
  29. package/dist/datasources/influx/index.d.ts +3 -0
  30. package/dist/datasources/influx/index.d.ts.map +1 -0
  31. package/dist/datasources/influx/index.js +8 -0
  32. package/dist/datasources/influx/index.js.map +1 -0
  33. package/dist/datasources/influx/influx-client.d.ts +16 -0
  34. package/dist/datasources/influx/influx-client.d.ts.map +1 -0
  35. package/dist/datasources/influx/influx-client.js +40 -0
  36. package/dist/datasources/influx/influx-client.js.map +1 -0
  37. package/dist/datasources/influx/influx-datasource.d.ts +18 -0
  38. package/dist/datasources/influx/influx-datasource.d.ts.map +1 -0
  39. package/dist/datasources/influx/influx-datasource.js +247 -0
  40. package/dist/datasources/influx/influx-datasource.js.map +1 -0
  41. package/dist/logger.d.ts +7 -0
  42. package/dist/logger.d.ts.map +1 -0
  43. package/dist/logger.js +47 -0
  44. package/dist/logger.js.map +1 -0
  45. package/dist/metrics/computations.d.ts +11 -0
  46. package/dist/metrics/computations.d.ts.map +1 -0
  47. package/dist/metrics/computations.js +247 -0
  48. package/dist/metrics/computations.js.map +1 -0
  49. package/dist/metrics/index.d.ts +2 -0
  50. package/dist/metrics/index.d.ts.map +1 -0
  51. package/dist/metrics/index.js +18 -0
  52. package/dist/metrics/index.js.map +1 -0
  53. package/dist/reporters/cli-reporter.d.ts.map +1 -1
  54. package/dist/reporters/cli-reporter.js +22 -60
  55. package/dist/reporters/cli-reporter.js.map +1 -1
  56. package/dist/reporters/markdown-reporter.d.ts.map +1 -1
  57. package/dist/reporters/markdown-reporter.js +19 -54
  58. package/dist/reporters/markdown-reporter.js.map +1 -1
  59. package/dist/reporters/slack-reporter.d.ts +5 -0
  60. package/dist/reporters/slack-reporter.d.ts.map +1 -1
  61. package/dist/reporters/slack-reporter.js +54 -84
  62. package/dist/reporters/slack-reporter.js.map +1 -1
  63. package/dist/types/index.d.ts +2 -0
  64. package/dist/types/index.d.ts.map +1 -0
  65. package/dist/types/index.js +18 -0
  66. package/dist/types/index.js.map +1 -0
  67. package/dist/types/metrics.d.ts +130 -0
  68. package/dist/types/metrics.d.ts.map +1 -0
  69. package/dist/types/metrics.js +3 -0
  70. package/dist/types/metrics.js.map +1 -0
  71. package/package.json +2 -3
  72. package/src/cache.ts +73 -0
  73. package/src/cli.ts +101 -27
  74. package/src/config.ts +47 -9
  75. package/src/data-collector.ts +102 -83
  76. package/src/datasources/datasource.ts +23 -0
  77. package/src/datasources/factory.ts +18 -0
  78. package/src/datasources/index.ts +3 -0
  79. package/src/datasources/influx/index.ts +2 -0
  80. package/src/{influx-client.ts → datasources/influx/influx-client.ts} +6 -1
  81. package/src/datasources/influx/influx-datasource.ts +355 -0
  82. package/src/logger.ts +49 -0
  83. package/src/metrics/computations.ts +315 -0
  84. package/src/metrics/index.ts +1 -0
  85. package/src/reporters/cli-reporter.ts +25 -65
  86. package/src/reporters/markdown-reporter.ts +22 -59
  87. package/src/reporters/slack-reporter.ts +62 -89
  88. package/src/types/index.ts +1 -0
  89. package/src/types/metrics.ts +150 -0
  90. package/src/influx-data-extractor.ts +0 -911
@@ -0,0 +1,18 @@
1
+ {
2
+ "permissions": {
3
+ "allow": [
4
+ "Bash(npm run *)",
5
+ "Bash(npx tsc *)",
6
+ "Bash(git checkout *)",
7
+ "Bash(git add *)",
8
+ "Bash(git commit -m ' *)",
9
+ "Bash(git push *)",
10
+ "Bash(xargs cat *)",
11
+ "Bash(npm test *)",
12
+ "Bash(git commit *)",
13
+ "Bash(git pull *)",
14
+ "Bash(git stash *)",
15
+ "Bash(wc *)"
16
+ ]
17
+ }
18
+ }
@@ -8,5 +8,8 @@
8
8
  "slack": {
9
9
  "token": "${SLACK_TOKEN}",
10
10
  "channel": "#k6-reports"
11
+ },
12
+ "cache": {
13
+ "ttl": 3600
11
14
  }
12
15
  }
@@ -0,0 +1,11 @@
1
+ import { ReporterResponse } from "./data-collector";
2
+ export declare class Cache {
3
+ private cacheDir;
4
+ private ttlMs;
5
+ constructor(ttlSeconds: number, cacheDir?: string);
6
+ private getCacheKey;
7
+ private getCachePath;
8
+ get(runId: string, startTime: string, endTime: string): ReporterResponse | null;
9
+ set(runId: string, startTime: string, endTime: string, data: ReporterResponse): void;
10
+ }
11
+ //# sourceMappingURL=cache.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cache.d.ts","sourceRoot":"","sources":["../src/cache.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AAQpD,qBAAa,KAAK;IAChB,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,KAAK,CAAS;gBAEV,UAAU,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM;IAKjD,OAAO,CAAC,WAAW;IAKnB,OAAO,CAAC,YAAY;IAIpB,GAAG,CAAC,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,gBAAgB,GAAG,IAAI;IA2B/E,GAAG,CAAC,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,gBAAgB,GAAG,IAAI;CAgBrF"}
package/dist/cache.js ADDED
@@ -0,0 +1,61 @@
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.Cache = void 0;
7
+ const fs_1 = __importDefault(require("fs"));
8
+ const path_1 = __importDefault(require("path"));
9
+ const crypto_1 = __importDefault(require("crypto"));
10
+ const logger_1 = require("./logger");
11
+ class Cache {
12
+ constructor(ttlSeconds, cacheDir) {
13
+ this.ttlMs = ttlSeconds * 1000;
14
+ this.cacheDir = cacheDir || path_1.default.resolve(".cache");
15
+ }
16
+ getCacheKey(runId, startTime, endTime) {
17
+ const raw = `${runId}:${startTime}:${endTime}`;
18
+ return crypto_1.default.createHash("md5").update(raw).digest("hex");
19
+ }
20
+ getCachePath(key) {
21
+ return path_1.default.join(this.cacheDir, `${key}.json`);
22
+ }
23
+ get(runId, startTime, endTime) {
24
+ const key = this.getCacheKey(runId, startTime, endTime);
25
+ const filePath = this.getCachePath(key);
26
+ if (!fs_1.default.existsSync(filePath)) {
27
+ logger_1.logger.debug(`Cache.get: miss (no file) key=${key}`);
28
+ return null;
29
+ }
30
+ try {
31
+ const raw = fs_1.default.readFileSync(filePath, "utf-8");
32
+ const entry = JSON.parse(raw);
33
+ if (Date.now() - entry.timestamp > this.ttlMs) {
34
+ logger_1.logger.debug(`Cache.get: expired key=${key}, age=${Math.round((Date.now() - entry.timestamp) / 1000)}s, ttl=${Math.round(this.ttlMs / 1000)}s`);
35
+ fs_1.default.unlinkSync(filePath);
36
+ return null;
37
+ }
38
+ logger_1.logger.debug(`Cache.get: hit key=${key}, age=${Math.round((Date.now() - entry.timestamp) / 1000)}s`);
39
+ return entry.data;
40
+ }
41
+ catch {
42
+ logger_1.logger.warn(`Cache.get: failed to read cache file ${filePath}`);
43
+ return null;
44
+ }
45
+ }
46
+ set(runId, startTime, endTime, data) {
47
+ const key = this.getCacheKey(runId, startTime, endTime);
48
+ const filePath = this.getCachePath(key);
49
+ if (!fs_1.default.existsSync(this.cacheDir)) {
50
+ fs_1.default.mkdirSync(this.cacheDir, { recursive: true });
51
+ }
52
+ const entry = {
53
+ timestamp: Date.now(),
54
+ data,
55
+ };
56
+ fs_1.default.writeFileSync(filePath, JSON.stringify(entry, null, 2), "utf-8");
57
+ logger_1.logger.debug(`Cache.set: wrote key=${key} to ${filePath}`);
58
+ }
59
+ }
60
+ exports.Cache = Cache;
61
+ //# sourceMappingURL=cache.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cache.js","sourceRoot":"","sources":["../src/cache.ts"],"names":[],"mappings":"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"}
package/dist/cli.js CHANGED
@@ -4,11 +4,45 @@ Object.defineProperty(exports, "__esModule", { value: true });
4
4
  const commander_1 = require("commander");
5
5
  const config_1 = require("./config");
6
6
  const data_collector_1 = require("./data-collector");
7
+ const datasources_1 = require("./datasources");
7
8
  const reporters_1 = require("./reporters");
9
+ const VALID_REPORTERS = ["cli", "json", "markdown", "slack"];
10
+ function defaultOutputPath(name, runId) {
11
+ const extensions = {
12
+ json: "json",
13
+ markdown: "md",
14
+ };
15
+ const ext = extensions[name];
16
+ return ext ? `report-${runId}.${ext}` : undefined;
17
+ }
18
+ async function runReporter(name, report, options, configInstance) {
19
+ const output = options.output || defaultOutputPath(name, report.runId);
20
+ switch (name) {
21
+ case "json":
22
+ new reporters_1.JsonReporter().report(report, output);
23
+ break;
24
+ case "markdown":
25
+ new reporters_1.MarkdownReporter().report(report, output);
26
+ break;
27
+ case "slack": {
28
+ const slackConfig = configInstance.getSlackConfig();
29
+ if (!slackConfig) {
30
+ throw new Error("Slack token not configured. Set SLACK_TOKEN environment variable or configure in config file.");
31
+ }
32
+ const slackReporter = new reporters_1.SlackReporter(slackConfig.token, slackConfig.channel);
33
+ await slackReporter.report(report);
34
+ console.log("Report sent to Slack");
35
+ break;
36
+ }
37
+ case "cli":
38
+ new reporters_1.CliReporter().report(report);
39
+ break;
40
+ }
41
+ }
8
42
  function main() {
9
43
  commander_1.program
10
44
  .name("k6-reporter")
11
- .description("Generate CLI reports from k6 tests stored in InfluxDB")
45
+ .description("Generate CLI reports from k6 performance tests")
12
46
  .version("1.6.0");
13
47
  commander_1.program
14
48
  .command("generate")
@@ -17,33 +51,34 @@ function main() {
17
51
  .option("-st, --start-time <time>", "Start time in ISO 8601 format or relative like '-1h'")
18
52
  .option("-et, --end-time <time>", "End time in ISO 8601 format (defaults to now)")
19
53
  .option("-c, --config <path>", "Path to config file", ".config.json")
54
+ .option("-d, --datasource <type>", "Data source: 'influxdb' or 'prometheus'")
20
55
  .option("-f, --format <format>", "Output format: 'json', 'cli', 'markdown', or 'slack'", "cli")
21
- .option("-o, --output <path>", "Output file path (for json format)")
56
+ .option("-r, --report <reporters>", "Run one or more reporters (comma-separated): cli, json, markdown, slack")
57
+ .option("-o, --output <path>", "Output file path (for json and markdown formats)")
58
+ .option("--no-cache", "Disable cache, always fetch fresh data")
22
59
  .action(async (options) => {
23
60
  try {
24
- const config = config_1.Config.getInstance(options.config).getInfluxConfig();
25
- const collector = new data_collector_1.DataCollector(config);
26
- const report = await collector.collect(options.runId, options.startTime || "-1h", options.endTime || "now()");
27
- if (options.format === "json") {
28
- const jsonReporter = new reporters_1.JsonReporter();
29
- jsonReporter.report(report, options.output);
30
- }
31
- else if (options.format === "markdown") {
32
- const markdownReporter = new reporters_1.MarkdownReporter();
33
- markdownReporter.report(report, options.output);
61
+ if (options.report && options.format !== "cli") {
62
+ throw new Error("Cannot use --report and --format together. Use --report for multiple reporters.");
34
63
  }
35
- else if (options.format === "slack") {
36
- const slackConfig = config_1.Config.getInstance(options.config).getSlackConfig();
37
- if (!slackConfig) {
38
- throw new Error("Slack token not configured. Set SLACK_TOKEN environment variable or configure in config file.");
64
+ const configInstance = config_1.Config.getInstance(options.config);
65
+ const dsType = (options.datasource || configInstance.getDataSourceType());
66
+ const dataSource = (0, datasources_1.createDataSource)(dsType, configInstance);
67
+ const cacheTtl = options.cache ? configInstance.getCacheConfig().ttl : 0;
68
+ const collector = new data_collector_1.DataCollector(dataSource, cacheTtl);
69
+ const report = await collector.collect(options.runId, options.startTime || "-1h", options.endTime || "now()");
70
+ if (options.report) {
71
+ const reporters = options.report.split(",").map((r) => r.trim());
72
+ const invalid = reporters.filter((r) => !VALID_REPORTERS.includes(r));
73
+ if (invalid.length > 0) {
74
+ throw new Error(`Invalid reporter(s): ${invalid.join(", ")}. Valid options: ${VALID_REPORTERS.join(", ")}`);
75
+ }
76
+ for (const name of reporters) {
77
+ await runReporter(name, report, options, configInstance);
39
78
  }
40
- const slackReporter = new reporters_1.SlackReporter(slackConfig.token, slackConfig.channel);
41
- await slackReporter.report(report);
42
- console.log("Report sent to Slack");
43
79
  }
44
80
  else {
45
- const cliReporter = new reporters_1.CliReporter();
46
- cliReporter.report(report);
81
+ await runReporter(options.format, report, options, configInstance);
47
82
  }
48
83
  }
49
84
  catch (error) {
@@ -56,7 +91,7 @@ function main() {
56
91
  .description("Show help and examples")
57
92
  .action(() => {
58
93
  console.log(`
59
- k6-reporter - Generate CLI reports from k6 tests stored in InfluxDB
94
+ k6-reporter - Generate reports from k6 performance tests
60
95
 
61
96
  USAGE:
62
97
  k6-reporter <command> [options]
@@ -73,8 +108,11 @@ OPTIONS:
73
108
  -st, --start-time Start time (relative: -1h, -30m, or ISO 8601)
74
109
  -et, --end-time End time (ISO 8601 format, defaults to now)
75
110
  -c, --config Path to config file (default: .config.json)
111
+ -d, --datasource Data source: 'influxdb' or 'prometheus' (default: influxdb)
76
112
  -f, --format Output format: 'json', 'cli', 'markdown', or 'slack' (default: cli)
113
+ -r, --report Run one or more reporters (comma-separated): cli, json, markdown, slack
77
114
  -o, --output Output file path (for json and markdown formats)
115
+ --no-cache Disable cache, always fetch fresh data
78
116
  -h, --help Show command help
79
117
  -V, --version Show version
80
118
 
@@ -101,9 +139,18 @@ EXAMPLES:
101
139
  7. Use custom config file:
102
140
  k6-reporter generate --run-id 123456790121 -c /path/to/config.json
103
141
 
104
- 8. Get help for generate command:
142
+ 8. Use Prometheus datasource:
143
+ k6-reporter generate --run-id 123456790121 -d prometheus
144
+
145
+ 9. Get help for generate command:
105
146
  k6-reporter generate --help
106
147
 
148
+ 10. Run multiple reporters at once:
149
+ k6-reporter generate --run-id 123456790121 --report cli,slack
150
+
151
+ 11. Generate Markdown and JSON reports together:
152
+ k6-reporter generate --run-id 123456790121 --report markdown,json -o report
153
+
107
154
  TIME FORMAT:
108
155
 
109
156
  Relative times (from now):
@@ -117,14 +164,28 @@ TIME FORMAT:
117
164
 
118
165
  CONFIG FILE:
119
166
 
120
- The config file (.config.json) should contain InfluxDB connection settings:
167
+ The config file (.config.json) supports multiple datasources:
121
168
 
122
169
  {
123
- "influxUrl": "https://influxdb.example.com",
124
- "influxToken": "your-influx-token",
125
- "influxOrg": "your-org",
126
- "influxBucket": "your-bucket"
170
+ "dataSource": "influxdb",
171
+ "influx": {
172
+ "url": "https://influxdb.example.com",
173
+ "token": "your-influx-token",
174
+ "org": "your-org",
175
+ "bucket": "your-bucket"
176
+ }
127
177
  }
178
+
179
+ ENVIRONMENT VARIABLES:
180
+
181
+ DATASOURCE Data source type (influxdb, prometheus)
182
+ INFLUX_URL InfluxDB URL
183
+ INFLUX_TOKEN InfluxDB token
184
+ INFLUX_ORG InfluxDB organization
185
+ INFLUX_BUCKET InfluxDB bucket
186
+ SLACK_TOKEN Slack bot token
187
+ SLACK_CHANNEL Slack channel ID
188
+ CACHE_TTL Cache TTL in seconds (default: 3600)
128
189
  `);
129
190
  });
130
191
  commander_1.program.parse();
package/dist/cli.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
package/dist/config.d.ts CHANGED
@@ -1,3 +1,4 @@
1
+ export type DataSourceType = "influxdb" | "prometheus";
1
2
  export interface InfluxConfig {
2
3
  url: string;
3
4
  token: string;
@@ -8,18 +9,26 @@ export interface SlackConfig {
8
9
  token: string;
9
10
  channel: string;
10
11
  }
12
+ export interface CacheConfig {
13
+ ttl: number;
14
+ }
11
15
  export declare class Config {
12
16
  private static instance;
13
- private influxConfig;
17
+ private dataSourceType;
18
+ private rawInflux;
14
19
  private slackConfig;
20
+ private cacheConfig;
15
21
  private configPath;
16
22
  private constructor();
17
23
  private loadRawConfig;
18
- private parseInfluxConfig;
24
+ private parseDataSourceType;
25
+ getInfluxConfig(): InfluxConfig;
19
26
  private parseSlackConfig;
27
+ private parseCacheConfig;
20
28
  private resolveValue;
21
29
  static getInstance(configPath?: string): Config;
22
- getInfluxConfig(): InfluxConfig;
30
+ getDataSourceType(): DataSourceType;
23
31
  getSlackConfig(): SlackConfig | null;
32
+ getCacheConfig(): CacheConfig;
24
33
  }
25
34
  //# sourceMappingURL=config.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,YAAY;IAC3B,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;CACjB;AAOD,qBAAa,MAAM;IACjB,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAS;IAChC,OAAO,CAAC,YAAY,CAAe;IACnC,OAAO,CAAC,WAAW,CAA4B;IAC/C,OAAO,CAAC,UAAU,CAAS;IAE3B,OAAO;IAOP,OAAO,CAAC,aAAa;IAerB,OAAO,CAAC,iBAAiB;IAgBzB,OAAO,CAAC,gBAAgB;IAiBxB,OAAO,CAAC,YAAY;IAWpB,MAAM,CAAC,WAAW,CAAC,UAAU,CAAC,EAAE,MAAM,GAAG,MAAM;IAO/C,eAAe,IAAI,YAAY;IAI/B,cAAc,IAAI,WAAW,GAAG,IAAI;CAGrC"}
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAGA,MAAM,MAAM,cAAc,GAAG,UAAU,GAAG,YAAY,CAAC;AAEvD,MAAM,WAAW,YAAY;IAC3B,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,WAAW;IAC1B,GAAG,EAAE,MAAM,CAAC;CACb;AASD,qBAAa,MAAM;IACjB,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAS;IAChC,OAAO,CAAC,cAAc,CAAiB;IACvC,OAAO,CAAC,SAAS,CAAsC;IACvD,OAAO,CAAC,WAAW,CAA4B;IAC/C,OAAO,CAAC,WAAW,CAAc;IACjC,OAAO,CAAC,UAAU,CAAS;IAE3B,OAAO;IASP,OAAO,CAAC,aAAa;IAerB,OAAO,CAAC,mBAAmB;IAS3B,eAAe,IAAI,YAAY;IAgB/B,OAAO,CAAC,gBAAgB;IAiBxB,OAAO,CAAC,gBAAgB;IAaxB,OAAO,CAAC,YAAY;IAWpB,MAAM,CAAC,WAAW,CAAC,UAAU,CAAC,EAAE,MAAM,GAAG,MAAM;IAO/C,iBAAiB,IAAI,cAAc;IAInC,cAAc,IAAI,WAAW,GAAG,IAAI;IAIpC,cAAc,IAAI,WAAW;CAG9B"}
package/dist/config.js CHANGED
@@ -11,8 +11,10 @@ class Config {
11
11
  this.slackConfig = null;
12
12
  this.configPath = configPath || ".config.json";
13
13
  const rawConfig = this.loadRawConfig();
14
- this.influxConfig = this.parseInfluxConfig(rawConfig.influx);
14
+ this.dataSourceType = this.parseDataSourceType(rawConfig.dataSource);
15
+ this.rawInflux = rawConfig.influx;
15
16
  this.slackConfig = this.parseSlackConfig(rawConfig.slack);
17
+ this.cacheConfig = this.parseCacheConfig(rawConfig.cache);
16
18
  }
17
19
  loadRawConfig() {
18
20
  const fullPath = path_1.default.resolve(this.configPath);
@@ -27,11 +29,19 @@ class Config {
27
29
  }
28
30
  return {};
29
31
  }
30
- parseInfluxConfig(rawConfig) {
31
- const url = this.resolveValue(rawConfig?.url, "INFLUX_URL");
32
- const token = this.resolveValue(rawConfig?.token, "INFLUX_TOKEN");
33
- const org = this.resolveValue(rawConfig?.org, "INFLUX_ORG");
34
- const bucket = this.resolveValue(rawConfig?.bucket, "INFLUX_BUCKET");
32
+ parseDataSourceType(raw) {
33
+ const envValue = process.env["DATASOURCE"];
34
+ const value = envValue || raw || "influxdb";
35
+ if (value !== "influxdb" && value !== "prometheus") {
36
+ throw new Error(`Unknown datasource type: '${value}'. Supported: influxdb, prometheus`);
37
+ }
38
+ return value;
39
+ }
40
+ getInfluxConfig() {
41
+ const url = this.resolveValue(this.rawInflux?.url, "INFLUX_URL");
42
+ const token = this.resolveValue(this.rawInflux?.token, "INFLUX_TOKEN");
43
+ const org = this.resolveValue(this.rawInflux?.org, "INFLUX_ORG");
44
+ const bucket = this.resolveValue(this.rawInflux?.bucket, "INFLUX_BUCKET");
35
45
  if (!url || !token || !org || !bucket) {
36
46
  throw new Error("InfluxDB configuration is incomplete. " +
37
47
  "Set INFLUX_URL, INFLUX_TOKEN, INFLUX_ORG, INFLUX_BUCKET via environment variables or config file.");
@@ -50,6 +60,18 @@ class Config {
50
60
  }
51
61
  return { token, channel };
52
62
  }
63
+ parseCacheConfig(rawConfig) {
64
+ const DEFAULT_TTL = 3600;
65
+ const envTtl = process.env["CACHE_TTL"];
66
+ if (envTtl) {
67
+ return { ttl: parseInt(envTtl, 10) };
68
+ }
69
+ const ttl = rawConfig?.ttl;
70
+ if (typeof ttl === "number") {
71
+ return { ttl };
72
+ }
73
+ return { ttl: DEFAULT_TTL };
74
+ }
53
75
  resolveValue(configValue, envVar) {
54
76
  // First check environment variable (takes priority)
55
77
  const envValue = process.env[envVar];
@@ -65,12 +87,15 @@ class Config {
65
87
  }
66
88
  return Config.instance;
67
89
  }
68
- getInfluxConfig() {
69
- return this.influxConfig;
90
+ getDataSourceType() {
91
+ return this.dataSourceType;
70
92
  }
71
93
  getSlackConfig() {
72
94
  return this.slackConfig;
73
95
  }
96
+ getCacheConfig() {
97
+ return this.cacheConfig;
98
+ }
74
99
  }
75
100
  exports.Config = Config;
76
101
  //# sourceMappingURL=config.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
@@ -1,15 +1,12 @@
1
- import { InfluxConfig } from "./config";
2
- export interface ReporterResponse {
3
- runId: string;
4
- startTime: string;
5
- endTime: string;
6
- timestamp: string;
7
- data: unknown;
8
- }
1
+ import { DataSource } from "./datasources";
2
+ import { ReporterResponse } from "./types";
3
+ export { ReporterResponse } from "./types";
9
4
  export declare class DataCollector {
10
- private extractor;
5
+ private dataSource;
11
6
  private loader;
12
- constructor(config: InfluxConfig);
7
+ private cache;
8
+ constructor(dataSource: DataSource, cacheTtl?: number);
9
+ private formatElapsed;
13
10
  collect(runId: string, startTime?: string, endTime?: string, data?: unknown): Promise<ReporterResponse>;
14
11
  }
15
12
  //# sourceMappingURL=data-collector.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"data-collector.d.ts","sourceRoot":"","sources":["../src/data-collector.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AAGxC,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,OAAO,CAAC;CACf;AAED,qBAAa,aAAa;IACxB,OAAO,CAAC,SAAS,CAAsB;IACvC,OAAO,CAAC,MAAM,CAAgB;gBAElB,MAAM,EAAE,YAAY;IAI1B,OAAO,CACX,KAAK,EAAE,MAAM,EACb,SAAS,GAAE,MAAc,EACzB,OAAO,GAAE,MAAgB,EACzB,IAAI,GAAE,OAAY,GACjB,OAAO,CAAC,gBAAgB,CAAC;CAkG7B"}
1
+ {"version":3,"file":"data-collector.d.ts","sourceRoot":"","sources":["../src/data-collector.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAC3C,OAAO,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAC;AAe3C,OAAO,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAC;AAE3C,qBAAa,aAAa;IACxB,OAAO,CAAC,UAAU,CAAa;IAC/B,OAAO,CAAC,MAAM,CAAgB;IAC9B,OAAO,CAAC,KAAK,CAAe;gBAEhB,UAAU,EAAE,UAAU,EAAE,QAAQ,CAAC,EAAE,MAAM;IAKrD,OAAO,CAAC,aAAa;IAQf,OAAO,CACX,KAAK,EAAE,MAAM,EACb,SAAS,GAAE,MAAc,EACzB,OAAO,GAAE,MAAgB,EACzB,IAAI,GAAE,OAAY,GACjB,OAAO,CAAC,gBAAgB,CAAC;CAqG7B"}
@@ -1,65 +1,72 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.DataCollector = void 0;
4
- const influx_data_extractor_1 = require("./influx-data-extractor");
4
+ const metrics_1 = require("./metrics");
5
5
  const loader_1 = require("./loader");
6
+ const cache_1 = require("./cache");
7
+ const logger_1 = require("./logger");
6
8
  class DataCollector {
7
- constructor(config) {
9
+ constructor(dataSource, cacheTtl) {
8
10
  this.loader = new loader_1.Loader();
9
- this.extractor = new influx_data_extractor_1.InfluxDataExtractor(config);
11
+ this.dataSource = dataSource;
12
+ this.cache = cacheTtl != null && cacheTtl > 0 ? new cache_1.Cache(cacheTtl) : null;
13
+ }
14
+ formatElapsed(ms) {
15
+ const seconds = Math.floor(ms / 1000);
16
+ if (seconds < 60)
17
+ return `${seconds}s`;
18
+ const minutes = Math.floor(seconds / 60);
19
+ const remainingSeconds = seconds % 60;
20
+ return remainingSeconds > 0 ? `${minutes}m ${remainingSeconds}s` : `${minutes}m`;
10
21
  }
11
22
  async collect(runId, startTime = "-1h", endTime = "now()", data = {}) {
12
- this.loader.start("Extracting http_reqs...");
13
- const httpReqs = await this.extractor.extractHttpReqs(runId, startTime, endTime);
14
- this.loader.success("Extracted http_reqs");
15
- this.loader.start("Extracting vus...");
16
- const vus = await this.extractor.extractVus(runId, startTime, endTime);
17
- this.loader.success("Extracted vus");
18
- this.loader.start("Extracting vus_max...");
19
- const vusMax = await this.extractor.extractVusMax(runId, startTime, endTime);
20
- this.loader.success("Extracted vus_max");
21
- this.loader.start("Extracting iterations...");
22
- const iterations = await this.extractor.extractIterations(runId, startTime, endTime);
23
- this.loader.success("Extracted iterations");
24
- this.loader.start("Calculating test duration...");
25
- const duration = await this.extractor.calculateTestDuration(runId, startTime, endTime);
26
- this.loader.success("Calculated test duration");
27
- this.loader.start("Extracting checks...");
28
- const checks = await this.extractor.extractChecks(runId, startTime, endTime);
29
- this.loader.success("Extracted checks");
30
- this.loader.start("Extracting http_req_failed...");
31
- const httpReqFailed = await this.extractor.extractHttpReqFailed(runId, startTime, endTime);
32
- this.loader.success("Extracted http_req_failed");
33
- this.loader.start("Extracting http_req_duration...");
34
- const httpReqDuration = await this.extractor.extractHttpReqDuration(runId, startTime, endTime);
35
- this.loader.success("Extracted http_req_duration");
36
- this.loader.start("Extracting http_req_duration (success only)...");
37
- const httpReqDurationSuccess = await this.extractor.extractHttpReqDurationSuccess(runId, startTime, endTime);
38
- this.loader.success("Extracted http_req_duration (success only)");
39
- this.loader.start("Extracting iteration_duration...");
40
- const iterationDuration = await this.extractor.extractIterationDuration(runId, startTime, endTime);
41
- this.loader.success("Extracted iteration_duration");
42
- this.loader.start("Extracting error_responses...");
43
- const errorResponses = await this.extractor.extractErrorResponses(runId, startTime, endTime);
44
- this.loader.success("Extracted error_responses");
45
- this.loader.start("Extracting top slow URLs...");
46
- const topSlowUrls = await this.extractor.extractTopSlowUrls(runId, startTime, endTime);
47
- this.loader.success("Extracted top slow URLs");
48
- this.loader.start("Extracting error requests...");
49
- const errorRequests = await this.extractor.extractErrorRequests(runId, startTime, endTime);
50
- this.loader.success("Extracted error requests");
51
- this.loader.start("Extracting success requests...");
52
- const successRequests = await this.extractor.extractSuccessRequests(runId, startTime, endTime);
53
- this.loader.success("Extracted success requests");
54
- this.loader.start("Extracting error responses text...");
55
- const errorResponsesText = await this.extractor.extractErrorResponsesText(runId, startTime, endTime);
56
- this.loader.success("Extracted error responses text");
57
- this.loader.start("Extracting RPS per URL...");
58
- const rpsPerUrl = await this.extractor.extractRpsPerUrl(runId, startTime, endTime);
59
- this.loader.success("Extracted RPS per URL");
60
- this.loader.start("Extracting RPS aggregated (5s intervals)...");
61
- const rpsAggregated = await this.extractor.extractRpsAggregated(runId, startTime, endTime);
62
- this.loader.success("Extracted RPS aggregated");
23
+ logger_1.logger.info(`DataCollector.collect: runId=${runId}, range=[${startTime}, ${endTime}]`);
24
+ if (this.cache) {
25
+ const cached = this.cache.get(runId, startTime, endTime);
26
+ if (cached) {
27
+ logger_1.logger.info("DataCollector.collect: cache hit, skipping data fetch");
28
+ this.loader.success("Loaded report from cache");
29
+ return cached;
30
+ }
31
+ logger_1.logger.debug("DataCollector.collect: cache miss, fetching from datasource");
32
+ }
33
+ // Phase 1: Parallel bulk fetch — all independent queries at once
34
+ this.loader.start("Fetching all data in parallel...");
35
+ const fetchStart = Date.now();
36
+ logger_1.logger.info("DataCollector.collect: starting parallel data fetch (9 queries)");
37
+ const [httpReqsData, httpReqDurationData, duration, vus, vusMax, iterations, checks, iterationDuration, errorResponsesText,] = await Promise.all([
38
+ this.dataSource.fetchHttpReqsData(runId, startTime, endTime),
39
+ this.dataSource.fetchHttpReqDurationData(runId, startTime, endTime),
40
+ this.dataSource.calculateTestDuration(runId, startTime, endTime),
41
+ this.dataSource.extractVus(runId, startTime, endTime),
42
+ this.dataSource.extractVusMax(runId, startTime, endTime),
43
+ this.dataSource.extractIterations(runId, startTime, endTime),
44
+ this.dataSource.extractChecks(runId, startTime, endTime),
45
+ this.dataSource.extractIterationDuration(runId, startTime, endTime),
46
+ this.dataSource.extractErrorResponsesText(runId, startTime, endTime),
47
+ ]);
48
+ const fetchElapsed = Date.now() - fetchStart;
49
+ logger_1.logger.info(`DataCollector.collect: parallel fetch completed in ${fetchElapsed}ms`);
50
+ logger_1.logger.debug(`DataCollector.collect: fetched rows — httpReqs=${httpReqsData.length}, httpReqDuration=${httpReqDurationData.length}, ` +
51
+ `errorResponsesText=${errorResponsesText.responses.length}`);
52
+ this.loader.success(`Data fetching finished in ${this.formatElapsed(fetchElapsed)}`);
53
+ // Phase 2: Derive metrics from cached data (no additional queries)
54
+ this.loader.start("Computing metrics...");
55
+ logger_1.logger.info("DataCollector.collect: computing derived metrics");
56
+ // Update iterations with duration info
57
+ if (iterations.total > 0 && duration.durationSeconds > 0) {
58
+ iterations.rate = iterations.total / duration.durationSeconds;
59
+ }
60
+ const httpReqs = (0, metrics_1.extractHttpReqsFromData)(httpReqsData, duration);
61
+ const httpReqFailed = (0, metrics_1.extractHttpReqFailedFromData)(httpReqsData);
62
+ const httpReqDuration = (0, metrics_1.extractHttpReqDurationFromData)(httpReqDurationData);
63
+ const httpReqDurationSuccess = (0, metrics_1.extractHttpReqDurationSuccessFromData)(httpReqDurationData);
64
+ const errorResponses = (0, metrics_1.extractErrorResponsesFromData)(httpReqsData, duration);
65
+ const errorRequests = (0, metrics_1.extractErrorRequestsFromData)(httpReqsData, httpReqDurationData);
66
+ const requests = (0, metrics_1.extractRequestsFromData)(httpReqsData, httpReqDurationData);
67
+ const rpsAggregated = (0, metrics_1.extractRpsAggregatedFromData)(httpReqsData);
68
+ logger_1.logger.info("DataCollector.collect: all metrics computed");
69
+ this.loader.success("Computed all metrics");
63
70
  const reportData = {
64
71
  ...(typeof data === "object" && data !== null ? data : {}),
65
72
  httpReqs,
@@ -73,20 +80,23 @@ class DataCollector {
73
80
  httpReqDurationSuccess,
74
81
  iterationDuration,
75
82
  errorResponses,
76
- rpsPerUrl,
77
- topSlowUrls,
83
+ requests,
78
84
  errorRequests,
79
- successRequests,
80
85
  errorResponsesText,
81
86
  rpsAggregated,
82
87
  };
83
- return {
88
+ const result = {
84
89
  runId,
85
90
  startTime: duration.startTime || startTime,
86
91
  endTime: duration.endTime || endTime,
87
92
  timestamp: new Date().toISOString(),
88
93
  data: reportData,
89
94
  };
95
+ if (this.cache) {
96
+ this.cache.set(runId, startTime, endTime, result);
97
+ logger_1.logger.debug("DataCollector.collect: result cached");
98
+ }
99
+ return result;
90
100
  }
91
101
  }
92
102
  exports.DataCollector = DataCollector;