@loadstrike/loadstrike-sdk 1.0.23001 → 1.0.23201
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/dist/cjs/index.js +2 -1
- package/dist/cjs/local.js +5 -1
- package/dist/cjs/runtime.js +52 -1
- package/dist/cjs/sinks.js +123 -19
- package/dist/esm/index.js +1 -1
- package/dist/esm/local.js +5 -1
- package/dist/esm/runtime.js +52 -1
- package/dist/esm/sinks.js +121 -18
- package/dist/types/index.d.ts +2 -2
- package/dist/types/local.d.ts +1 -0
- package/dist/types/runtime.d.ts +13 -0
- package/dist/types/sinks.d.ts +37 -4
- package/package.json +1 -1
package/dist/cjs/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.InfluxDbReportingSink = exports.GrafanaLokiReportingSinkOptions = exports.GrafanaLokiReportingSink = exports.DatadogReportingSinkOptions = exports.DatadogReportingSink = exports.HttpAuthOptions = exports.HttpOAuth2ClientCredentialsOptions = exports.PushDiffusionEndpointDefinition = exports.DelegateStreamEndpointDefinition = exports.SqsEndpointDefinition = exports.AzureEventHubsEndpointDefinition = exports.RedisStreamsEndpointDefinition = exports.NatsEndpointDefinition = exports.RabbitMqEndpointDefinition = exports.KafkaSaslOptions = exports.KafkaEndpointDefinition = exports.HttpEndpointDefinition = exports.TrafficEndpointDefinition = exports.LOADSTRIKE_TRACE_ID_TRACKING_FIELD = exports.LOADSTRIKE_TRACE_ID_HEADER = exports.TrackingFieldSelector = exports.TrackingPayloadBuilder = exports.RedisCorrelationStore = exports.RedisCorrelationStoreOptions = exports.InMemoryCorrelationStore = exports.CrossPlatformTrackingRuntime = exports.CorrelationStoreConfiguration = exports.LoadStrikeThreshold = exports.LoadStrikeStep = exports.LoadStrikeGauge = exports.LoadStrikeCounter = exports.LoadStrikeMetric = exports.CrossPlatformTrackingConfiguration = exports.LoadStrikeSimulation = exports.LoadStrikeScenario = exports.LoadStrikeRunner = exports.LoadStrikeOperationType = exports.LoadStrikeScenarioOperation = exports.LoadStrikeLogLevel = exports.LoadStrikeResponse = exports.LoadStrikeReportFormat = exports.LoadStrikeNodeType = exports.LoadStrikePluginDataTable = exports.LoadStrikePluginData = exports.LoadStrikeContext = exports.ScenarioTrackingExtensions = exports.CrossPlatformScenarioConfigurator = exports.LoadStrikeAutopilotReadiness = exports.LoadStrikeAutopilotResult = exports.LoadStrikeAutopilot = void 0;
|
|
4
|
-
exports.TimescaleDbReportingSinkOptions = exports.TimescaleDbReportingSink = exports.SplunkReportingSinkOptions = exports.SplunkReportingSink = exports.OtelCollectorReportingSinkOptions = exports.OtelCollectorReportingSink = exports.InfluxDbReportingSinkOptions = void 0;
|
|
4
|
+
exports.TimescaleDbReportingSinkOptions = exports.TimescaleDbReportingSink = exports.SplunkReportingSinkOptions = exports.SplunkReportingSink = exports.PortalReportingSink = exports.OtelCollectorReportingSinkOptions = exports.OtelCollectorReportingSink = exports.InfluxDbReportingSinkOptions = void 0;
|
|
5
5
|
var autopilot_js_1 = require("./autopilot.js");
|
|
6
6
|
Object.defineProperty(exports, "LoadStrikeAutopilot", { enumerable: true, get: function () { return autopilot_js_1.LoadStrikeAutopilot; } });
|
|
7
7
|
Object.defineProperty(exports, "LoadStrikeAutopilotResult", { enumerable: true, get: function () { return autopilot_js_1.LoadStrikeAutopilotResult; } });
|
|
@@ -61,6 +61,7 @@ Object.defineProperty(exports, "InfluxDbReportingSink", { enumerable: true, get:
|
|
|
61
61
|
Object.defineProperty(exports, "InfluxDbReportingSinkOptions", { enumerable: true, get: function () { return sinks_js_1.InfluxDbReportingSinkOptions; } });
|
|
62
62
|
Object.defineProperty(exports, "OtelCollectorReportingSink", { enumerable: true, get: function () { return sinks_js_1.OtelCollectorReportingSink; } });
|
|
63
63
|
Object.defineProperty(exports, "OtelCollectorReportingSinkOptions", { enumerable: true, get: function () { return sinks_js_1.OtelCollectorReportingSinkOptions; } });
|
|
64
|
+
Object.defineProperty(exports, "PortalReportingSink", { enumerable: true, get: function () { return sinks_js_1.PortalReportingSink; } });
|
|
64
65
|
Object.defineProperty(exports, "SplunkReportingSink", { enumerable: true, get: function () { return sinks_js_1.SplunkReportingSink; } });
|
|
65
66
|
Object.defineProperty(exports, "SplunkReportingSinkOptions", { enumerable: true, get: function () { return sinks_js_1.SplunkReportingSinkOptions; } });
|
|
66
67
|
Object.defineProperty(exports, "TimescaleDbReportingSink", { enumerable: true, get: function () { return sinks_js_1.TimescaleDbReportingSink; } });
|
package/dist/cjs/local.js
CHANGED
|
@@ -55,7 +55,8 @@ const SINK_FEATURE_BY_KIND = {
|
|
|
55
55
|
grafanaloki: "extensions.reporting_sinks.grafana_loki",
|
|
56
56
|
datadog: "extensions.reporting_sinks.datadog",
|
|
57
57
|
splunk: "extensions.reporting_sinks.splunk",
|
|
58
|
-
otelcollector: "extensions.reporting_sinks.otel_collector"
|
|
58
|
+
otelcollector: "extensions.reporting_sinks.otel_collector",
|
|
59
|
+
portal: "extensions.reporting_sinks.portal"
|
|
59
60
|
};
|
|
60
61
|
const TRACKING_FEATURE_BY_KIND = {
|
|
61
62
|
http: "endpoint.http",
|
|
@@ -96,6 +97,9 @@ class LoadStrikeLocalClient {
|
|
|
96
97
|
this.licensingApiBaseUrl = resolveLicensingApiBaseUrl();
|
|
97
98
|
this.licenseValidationTimeoutMs = normalizeTimeoutMs(options.licenseValidationTimeoutMs);
|
|
98
99
|
}
|
|
100
|
+
portalReportingIngestUrl() {
|
|
101
|
+
return `${this.licensingApiBaseUrl.replace(/\/+$/, "")}/api/v1/reporting/ingest`;
|
|
102
|
+
}
|
|
99
103
|
async run(request) {
|
|
100
104
|
const sanitized = sanitizeRequest(request);
|
|
101
105
|
const licenseSession = await this.acquireLicenseLease(sanitized);
|
package/dist/cjs/runtime.js
CHANGED
|
@@ -13,6 +13,7 @@ const cluster_js_1 = require("./cluster.js");
|
|
|
13
13
|
const correlation_js_1 = require("./correlation.js");
|
|
14
14
|
const transports_js_1 = require("./transports.js");
|
|
15
15
|
const reporting_js_1 = require("./reporting.js");
|
|
16
|
+
const sinks_js_1 = require("./sinks.js");
|
|
16
17
|
exports.LoadStrikeNodeType = {
|
|
17
18
|
SingleNode: "SingleNode",
|
|
18
19
|
Coordinator: "Coordinator",
|
|
@@ -1395,6 +1396,16 @@ class LoadStrikeContext {
|
|
|
1395
1396
|
validateNamedReportingSinks(sinks);
|
|
1396
1397
|
return this.mergeValues({ ReportingSinks: sinks });
|
|
1397
1398
|
}
|
|
1399
|
+
withPortalReporting() {
|
|
1400
|
+
return this.WithPortalReporting();
|
|
1401
|
+
}
|
|
1402
|
+
WithPortalReporting() {
|
|
1403
|
+
const sinks = [...(this.values.ReportingSinks ?? [])];
|
|
1404
|
+
if (!sinks.some((sink, index) => resolveSinkName(sink, index).trim().toLowerCase() === "portal")) {
|
|
1405
|
+
sinks.push(new sinks_js_1.PortalReportingSink());
|
|
1406
|
+
}
|
|
1407
|
+
return this.mergeValues({ ReportingSinks: sinks });
|
|
1408
|
+
}
|
|
1398
1409
|
/**
|
|
1399
1410
|
* Registers runtime policies for the run.
|
|
1400
1411
|
* Use this when scenario selection or step execution should obey policy callbacks.
|
|
@@ -2137,6 +2148,9 @@ class LoadStrikeRunner {
|
|
|
2137
2148
|
static WithReportingSinks(context, ...sinks) {
|
|
2138
2149
|
return context.WithReportingSinks(...sinks);
|
|
2139
2150
|
}
|
|
2151
|
+
static WithPortalReporting(context) {
|
|
2152
|
+
return context.WithPortalReporting();
|
|
2153
|
+
}
|
|
2140
2154
|
/**
|
|
2141
2155
|
* Registers runtime policies for the run.
|
|
2142
2156
|
* Use this when scenario selection or step execution should obey policy callbacks.
|
|
@@ -2365,6 +2379,29 @@ class LoadStrikeRunner {
|
|
|
2365
2379
|
WithReportingInterval(intervalSeconds) {
|
|
2366
2380
|
return this.withReportingInterval(intervalSeconds);
|
|
2367
2381
|
}
|
|
2382
|
+
withReportingSinks(...sinks) {
|
|
2383
|
+
if (!sinks.length) {
|
|
2384
|
+
throw new Error("At least one reporting sink should be provided.");
|
|
2385
|
+
}
|
|
2386
|
+
if (sinks.some((sink) => sink == null)) {
|
|
2387
|
+
throw new Error("Reporting sink collection cannot contain null values.");
|
|
2388
|
+
}
|
|
2389
|
+
validateNamedReportingSinks(sinks);
|
|
2390
|
+
return this.configure({ reportingSinks: sinks });
|
|
2391
|
+
}
|
|
2392
|
+
WithReportingSinks(...sinks) {
|
|
2393
|
+
return this.withReportingSinks(...sinks);
|
|
2394
|
+
}
|
|
2395
|
+
withPortalReporting() {
|
|
2396
|
+
const sinks = [...(this.options.reportingSinks ?? [])];
|
|
2397
|
+
if (!sinks.some((sink, index) => resolveSinkName(sink, index).trim().toLowerCase() === "portal")) {
|
|
2398
|
+
sinks.push(new sinks_js_1.PortalReportingSink());
|
|
2399
|
+
}
|
|
2400
|
+
return this.configure({ reportingSinks: sinks });
|
|
2401
|
+
}
|
|
2402
|
+
WithPortalReporting() {
|
|
2403
|
+
return this.withPortalReporting();
|
|
2404
|
+
}
|
|
2368
2405
|
/**
|
|
2369
2406
|
* Sets the timeout for cluster command round-trips.
|
|
2370
2407
|
* Use this when distributed control messages need a tighter or looser deadline.
|
|
@@ -2538,6 +2575,7 @@ class LoadStrikeRunner {
|
|
|
2538
2575
|
testInfo,
|
|
2539
2576
|
getNodeInfo: () => attachNodeInfoAliases({ ...nodeInfo })
|
|
2540
2577
|
};
|
|
2578
|
+
attachPortalReportingSession(sinkSession, sessionInfo, licenseClient, licenseSession);
|
|
2541
2579
|
attachSessionStartInfoAliases(sessionInfo);
|
|
2542
2580
|
nodeInfo.currentOperation = "Init";
|
|
2543
2581
|
for (const plugin of plugins) {
|
|
@@ -4072,10 +4110,23 @@ function attachSessionStartInfoAliases(session) {
|
|
|
4072
4110
|
attachAliasMap(session, {
|
|
4073
4111
|
StartedUtc: "startedUtc",
|
|
4074
4112
|
ScenarioNames: "scenarioNames",
|
|
4075
|
-
Scenarios: "scenarios"
|
|
4113
|
+
Scenarios: "scenarios",
|
|
4114
|
+
RunToken: "runToken",
|
|
4115
|
+
PortalReportingIngestUrl: "portalReportingIngestUrl"
|
|
4076
4116
|
});
|
|
4077
4117
|
return session;
|
|
4078
4118
|
}
|
|
4119
|
+
function attachPortalReportingSession(sinkSession, sessionInfo, licenseClient, licenseSession) {
|
|
4120
|
+
const runToken = stringValueOrDefault(licenseSession?.runToken, "").trim();
|
|
4121
|
+
if (!runToken || !licenseClient) {
|
|
4122
|
+
return;
|
|
4123
|
+
}
|
|
4124
|
+
const ingestUrl = licenseClient.portalReportingIngestUrl();
|
|
4125
|
+
sinkSession.runToken = runToken;
|
|
4126
|
+
sinkSession.portalReportingIngestUrl = ingestUrl;
|
|
4127
|
+
sessionInfo.runToken = runToken;
|
|
4128
|
+
sessionInfo.portalReportingIngestUrl = ingestUrl;
|
|
4129
|
+
}
|
|
4079
4130
|
function attachScenarioInitContextAliases(context) {
|
|
4080
4131
|
context.nodeInfo = attachNodeInfoAliases(context.nodeInfo);
|
|
4081
4132
|
context.testInfo = attachTestInfoAliases(context.testInfo);
|
package/dist/cjs/sinks.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.__loadstrikeTestExports = exports.OtelCollectorReportingSink = exports.SplunkReportingSink = exports.DatadogReportingSink = exports.TimescaleDbReportingSink = exports.GrafanaLokiReportingSink = exports.InfluxDbReportingSink = exports.CompositeReportingSink = exports.ConsoleReportingSink = exports.MemoryReportingSink = exports.OtelCollectorReportingSinkOptions = exports.SplunkReportingSinkOptions = exports.DatadogReportingSinkOptions = exports.TimescaleDbReportingSinkOptions = exports.GrafanaLokiReportingSinkOptions = exports.InfluxDbReportingSinkOptions = void 0;
|
|
3
|
+
exports.__loadstrikeTestExports = exports.OtelCollectorReportingSink = exports.SplunkReportingSink = exports.DatadogReportingSink = exports.TimescaleDbReportingSink = exports.GrafanaLokiReportingSink = exports.InfluxDbReportingSink = exports.PortalReportingSink = exports.CompositeReportingSink = exports.ConsoleReportingSink = exports.MemoryReportingSink = exports.OtelCollectorReportingSinkOptions = exports.SplunkReportingSinkOptions = exports.DatadogReportingSinkOptions = exports.TimescaleDbReportingSinkOptions = exports.GrafanaLokiReportingSinkOptions = exports.InfluxDbReportingSinkOptions = void 0;
|
|
4
4
|
const runtime_js_1 = require("./runtime.js");
|
|
5
|
+
const node_crypto_1 = require("node:crypto");
|
|
5
6
|
const pg_1 = require("pg");
|
|
6
7
|
const DEFAULT_INFLUX_CONFIGURATION_SECTION_PATH = "LoadStrike:ReportingSinks:InfluxDb";
|
|
7
8
|
const DEFAULT_GRAFANA_LOKI_CONFIGURATION_SECTION_PATH = "LoadStrike:ReportingSinks:GrafanaLoki";
|
|
@@ -384,6 +385,92 @@ class CompositeReportingSink {
|
|
|
384
385
|
}
|
|
385
386
|
}
|
|
386
387
|
exports.CompositeReportingSink = CompositeReportingSink;
|
|
388
|
+
class PortalReportingSink {
|
|
389
|
+
constructor(options = {}) {
|
|
390
|
+
this.sinkName = "portal";
|
|
391
|
+
this.SinkName = "portal";
|
|
392
|
+
this.licenseFeature = "extensions.reporting_sinks.portal";
|
|
393
|
+
this.LicenseFeature = "extensions.reporting_sinks.portal";
|
|
394
|
+
this.baseContext = null;
|
|
395
|
+
this.session = null;
|
|
396
|
+
this.runToken = "";
|
|
397
|
+
this.ingestUrl = "";
|
|
398
|
+
const source = asRecord(options);
|
|
399
|
+
this.timeoutMs = resolveTimeoutMs(optionNumber(source, "timeoutSeconds", "TimeoutSeconds"), optionNumber(source, "timeoutMs", "TimeoutMs"));
|
|
400
|
+
this.fetchImpl = pickRecordValue(source, "fetchImpl", "FetchImpl") ?? fetch;
|
|
401
|
+
}
|
|
402
|
+
init(context, _infraConfig) {
|
|
403
|
+
this.baseContext = cloneBaseContext(context);
|
|
404
|
+
}
|
|
405
|
+
Init(context, infraConfig) {
|
|
406
|
+
this.init(context, infraConfig);
|
|
407
|
+
}
|
|
408
|
+
start(session) {
|
|
409
|
+
this.runToken = String(session.runToken ?? session.RunToken ?? "").trim();
|
|
410
|
+
this.ingestUrl = String(session.portalReportingIngestUrl ?? session.PortalReportingIngestUrl ?? "").trim();
|
|
411
|
+
if (!this.runToken || !this.ingestUrl) {
|
|
412
|
+
throw new Error("PortalReportingSink requires a managed portal reporting session.");
|
|
413
|
+
}
|
|
414
|
+
this.session = sinkSessionMetadataFromContext(this.getBaseContext(), session);
|
|
415
|
+
}
|
|
416
|
+
Start(session) {
|
|
417
|
+
this.start(session);
|
|
418
|
+
}
|
|
419
|
+
async saveRealtimeStats(scenarioStats) {
|
|
420
|
+
await this.persistEvents(createRealtimeStatsEvents(this.getSession(), scenarioStats));
|
|
421
|
+
}
|
|
422
|
+
async SaveRealtimeStats(scenarioStats) {
|
|
423
|
+
await this.saveRealtimeStats(scenarioStats);
|
|
424
|
+
}
|
|
425
|
+
async saveRealtimeMetrics(metrics) {
|
|
426
|
+
await this.persistEvents(createRealtimeMetricEvents(this.getSession(), metrics));
|
|
427
|
+
}
|
|
428
|
+
async SaveRealtimeMetrics(metrics) {
|
|
429
|
+
await this.saveRealtimeMetrics(metrics);
|
|
430
|
+
}
|
|
431
|
+
async saveRunResult(result) {
|
|
432
|
+
await this.persistEvents(createRunResultEvents(this.getSession(), result));
|
|
433
|
+
}
|
|
434
|
+
async SaveRunResult(result) {
|
|
435
|
+
await this.saveRunResult(result);
|
|
436
|
+
}
|
|
437
|
+
stop() {
|
|
438
|
+
this.session = null;
|
|
439
|
+
}
|
|
440
|
+
Stop() {
|
|
441
|
+
this.stop();
|
|
442
|
+
}
|
|
443
|
+
Dispose() {
|
|
444
|
+
this.baseContext = null;
|
|
445
|
+
this.stop();
|
|
446
|
+
}
|
|
447
|
+
getBaseContext() {
|
|
448
|
+
if (!this.baseContext) {
|
|
449
|
+
throw new Error(`${this.sinkName} has not been initialized.`);
|
|
450
|
+
}
|
|
451
|
+
return this.baseContext;
|
|
452
|
+
}
|
|
453
|
+
getSession() {
|
|
454
|
+
if (!this.session) {
|
|
455
|
+
throw new Error(`${this.sinkName} has not been started.`);
|
|
456
|
+
}
|
|
457
|
+
return this.session;
|
|
458
|
+
}
|
|
459
|
+
async persistEvents(events) {
|
|
460
|
+
if (!events.length) {
|
|
461
|
+
return;
|
|
462
|
+
}
|
|
463
|
+
await postWithTimeout(this.fetchImpl, this.ingestUrl, {
|
|
464
|
+
method: "POST",
|
|
465
|
+
headers: { "Content-Type": "application/json" },
|
|
466
|
+
body: JSON.stringify({
|
|
467
|
+
runToken: this.runToken,
|
|
468
|
+
events: events.map((event, index) => portalEventPayload(event, index))
|
|
469
|
+
})
|
|
470
|
+
}, this.timeoutMs, "PortalReportingSink");
|
|
471
|
+
}
|
|
472
|
+
}
|
|
473
|
+
exports.PortalReportingSink = PortalReportingSink;
|
|
387
474
|
class InfluxDbReportingSink {
|
|
388
475
|
constructor(options = {}) {
|
|
389
476
|
this.sinkName = "influxdb";
|
|
@@ -1546,6 +1633,37 @@ function createReportingEvent(session, occurredUtc, eventType, scenarioName, ste
|
|
|
1546
1633
|
fields: eventFields
|
|
1547
1634
|
};
|
|
1548
1635
|
}
|
|
1636
|
+
function portalEventPayload(event, index) {
|
|
1637
|
+
return {
|
|
1638
|
+
eventId: portalEventId(event, index),
|
|
1639
|
+
runId: event.sessionId,
|
|
1640
|
+
eventType: event.eventType,
|
|
1641
|
+
occurredUtc: event.occurredUtc.toISOString(),
|
|
1642
|
+
sessionId: event.sessionId,
|
|
1643
|
+
testSuite: event.testSuite,
|
|
1644
|
+
testName: event.testName,
|
|
1645
|
+
clusterId: event.clusterId,
|
|
1646
|
+
nodeType: event.nodeType,
|
|
1647
|
+
machineName: event.machineName,
|
|
1648
|
+
scenarioName: event.scenarioName,
|
|
1649
|
+
stepName: event.stepName,
|
|
1650
|
+
tags: { ...event.tags },
|
|
1651
|
+
fields: deepCloneRecord(event.fields)
|
|
1652
|
+
};
|
|
1653
|
+
}
|
|
1654
|
+
function portalEventId(event, index) {
|
|
1655
|
+
const material = JSON.stringify({
|
|
1656
|
+
sessionId: event.sessionId,
|
|
1657
|
+
eventType: event.eventType,
|
|
1658
|
+
occurredUtc: event.occurredUtc.toISOString(),
|
|
1659
|
+
scenarioName: event.scenarioName ?? "",
|
|
1660
|
+
stepName: event.stepName ?? "",
|
|
1661
|
+
index,
|
|
1662
|
+
tags: event.tags,
|
|
1663
|
+
fields: event.fields
|
|
1664
|
+
});
|
|
1665
|
+
return `lsr_${(0, node_crypto_1.createHash)("sha256").update(material).digest("hex").slice(0, 40)}`;
|
|
1666
|
+
}
|
|
1549
1667
|
function addMeasurementFields(fields, prefix, measurement) {
|
|
1550
1668
|
const request = measurement?.request ?? { count: 0, percent: 0, rps: 0 };
|
|
1551
1669
|
const latency = measurement?.latency ?? {
|
|
@@ -2571,7 +2689,9 @@ function cloneSessionStartInfo(session) {
|
|
|
2571
2689
|
...cloneBaseContext(session),
|
|
2572
2690
|
startedUtc: session.startedUtc,
|
|
2573
2691
|
scenarioNames: [...session.scenarioNames],
|
|
2574
|
-
scenarios: session.scenarios.map((value) => ({ ...value }))
|
|
2692
|
+
scenarios: session.scenarios.map((value) => ({ ...value })),
|
|
2693
|
+
runToken: session.runToken,
|
|
2694
|
+
portalReportingIngestUrl: session.portalReportingIngestUrl
|
|
2575
2695
|
};
|
|
2576
2696
|
}
|
|
2577
2697
|
function cloneNodeInfo(nodeInfo) {
|
|
@@ -2673,23 +2793,7 @@ function runResultToNodeStats(result) {
|
|
|
2673
2793
|
disabledSinks: [...(result.disabledSinks ?? [])],
|
|
2674
2794
|
sinkErrors: (result.sinkErrors ?? []).map((value) => ({ ...value })),
|
|
2675
2795
|
reportFiles: [...(result.reportFiles ?? [])],
|
|
2676
|
-
logFiles: [...(result.logFiles ?? [])]
|
|
2677
|
-
findScenarioStats: (scenarioName) => result.scenarioStats.find((value) => value.scenarioName === scenarioName),
|
|
2678
|
-
getScenarioStats: (scenarioName) => {
|
|
2679
|
-
const scenario = result.scenarioStats.find((value) => value.scenarioName === scenarioName);
|
|
2680
|
-
if (!scenario) {
|
|
2681
|
-
throw new Error(`Scenario stats not found: ${scenarioName}`);
|
|
2682
|
-
}
|
|
2683
|
-
return scenario;
|
|
2684
|
-
},
|
|
2685
|
-
FindScenarioStats: (scenarioName) => result.scenarioStats.find((value) => value.scenarioName === scenarioName),
|
|
2686
|
-
GetScenarioStats: (scenarioName) => {
|
|
2687
|
-
const scenario = result.scenarioStats.find((value) => value.scenarioName === scenarioName);
|
|
2688
|
-
if (!scenario) {
|
|
2689
|
-
throw new Error(`Scenario stats not found: ${scenarioName}`);
|
|
2690
|
-
}
|
|
2691
|
-
return scenario;
|
|
2692
|
-
}
|
|
2796
|
+
logFiles: [...(result.logFiles ?? [])]
|
|
2693
2797
|
};
|
|
2694
2798
|
}
|
|
2695
2799
|
function deepCloneRecord(value) {
|
package/dist/esm/index.js
CHANGED
|
@@ -3,4 +3,4 @@ export { LoadStrikeAutopilotReadiness } from "./autopilot-contracts.js";
|
|
|
3
3
|
export { CrossPlatformScenarioConfigurator, ScenarioTrackingExtensions, LoadStrikeContext, LoadStrikePluginData, LoadStrikePluginDataTable, LoadStrikeNodeType, LoadStrikeReportFormat, LoadStrikeResponse, LoadStrikeLogLevel, LoadStrikeScenarioOperation, LoadStrikeOperationType, LoadStrikeRunner, LoadStrikeScenario, LoadStrikeSimulation, CrossPlatformTrackingConfiguration, LoadStrikeMetric, LoadStrikeCounter, LoadStrikeGauge, LoadStrikeStep, LoadStrikeThreshold } from "./runtime.js";
|
|
4
4
|
export { CorrelationStoreConfiguration, CrossPlatformTrackingRuntime, InMemoryCorrelationStore, RedisCorrelationStoreOptions, RedisCorrelationStore, TrackingPayloadBuilder, TrackingFieldSelector } from "./correlation.js";
|
|
5
5
|
export { LOADSTRIKE_TRACE_ID_HEADER, LOADSTRIKE_TRACE_ID_TRACKING_FIELD, TrafficEndpointDefinition, HttpEndpointDefinition, KafkaEndpointDefinition, KafkaSaslOptions, RabbitMqEndpointDefinition, NatsEndpointDefinition, RedisStreamsEndpointDefinition, AzureEventHubsEndpointDefinition, SqsEndpointDefinition, DelegateStreamEndpointDefinition, PushDiffusionEndpointDefinition, HttpOAuth2ClientCredentialsOptions, HttpAuthOptions } from "./transports.js";
|
|
6
|
-
export { DatadogReportingSink, DatadogReportingSinkOptions, GrafanaLokiReportingSink, GrafanaLokiReportingSinkOptions, InfluxDbReportingSink, InfluxDbReportingSinkOptions, OtelCollectorReportingSink, OtelCollectorReportingSinkOptions, SplunkReportingSink, SplunkReportingSinkOptions, TimescaleDbReportingSink, TimescaleDbReportingSinkOptions } from "./sinks.js";
|
|
6
|
+
export { DatadogReportingSink, DatadogReportingSinkOptions, GrafanaLokiReportingSink, GrafanaLokiReportingSinkOptions, InfluxDbReportingSink, InfluxDbReportingSinkOptions, OtelCollectorReportingSink, OtelCollectorReportingSinkOptions, PortalReportingSink, SplunkReportingSink, SplunkReportingSinkOptions, TimescaleDbReportingSink, TimescaleDbReportingSinkOptions } from "./sinks.js";
|
package/dist/esm/local.js
CHANGED
|
@@ -16,7 +16,8 @@ const SINK_FEATURE_BY_KIND = {
|
|
|
16
16
|
grafanaloki: "extensions.reporting_sinks.grafana_loki",
|
|
17
17
|
datadog: "extensions.reporting_sinks.datadog",
|
|
18
18
|
splunk: "extensions.reporting_sinks.splunk",
|
|
19
|
-
otelcollector: "extensions.reporting_sinks.otel_collector"
|
|
19
|
+
otelcollector: "extensions.reporting_sinks.otel_collector",
|
|
20
|
+
portal: "extensions.reporting_sinks.portal"
|
|
20
21
|
};
|
|
21
22
|
const TRACKING_FEATURE_BY_KIND = {
|
|
22
23
|
http: "endpoint.http",
|
|
@@ -57,6 +58,9 @@ export class LoadStrikeLocalClient {
|
|
|
57
58
|
this.licensingApiBaseUrl = resolveLicensingApiBaseUrl();
|
|
58
59
|
this.licenseValidationTimeoutMs = normalizeTimeoutMs(options.licenseValidationTimeoutMs);
|
|
59
60
|
}
|
|
61
|
+
portalReportingIngestUrl() {
|
|
62
|
+
return `${this.licensingApiBaseUrl.replace(/\/+$/, "")}/api/v1/reporting/ingest`;
|
|
63
|
+
}
|
|
60
64
|
async run(request) {
|
|
61
65
|
const sanitized = sanitizeRequest(request);
|
|
62
66
|
const licenseSession = await this.acquireLicenseLease(sanitized);
|
package/dist/esm/runtime.js
CHANGED
|
@@ -7,6 +7,7 @@ import { DistributedClusterAgent, DistributedClusterCoordinator } from "./cluste
|
|
|
7
7
|
import { CorrelationStoreConfiguration, CrossPlatformTrackingRuntime, RedisCorrelationStore, RedisCorrelationStoreOptions, TrackingFieldSelector } from "./correlation.js";
|
|
8
8
|
import { EndpointAdapterFactory, LOADSTRIKE_TRACE_ID_TRACKING_FIELD } from "./transports.js";
|
|
9
9
|
import { buildDotnetCsvReport, buildDotnetHtmlReport, buildDotnetMarkdownReport, buildDotnetTxtReport } from "./reporting.js";
|
|
10
|
+
import { PortalReportingSink } from "./sinks.js";
|
|
10
11
|
export const LoadStrikeNodeType = {
|
|
11
12
|
SingleNode: "SingleNode",
|
|
12
13
|
Coordinator: "Coordinator",
|
|
@@ -1378,6 +1379,16 @@ export class LoadStrikeContext {
|
|
|
1378
1379
|
validateNamedReportingSinks(sinks);
|
|
1379
1380
|
return this.mergeValues({ ReportingSinks: sinks });
|
|
1380
1381
|
}
|
|
1382
|
+
withPortalReporting() {
|
|
1383
|
+
return this.WithPortalReporting();
|
|
1384
|
+
}
|
|
1385
|
+
WithPortalReporting() {
|
|
1386
|
+
const sinks = [...(this.values.ReportingSinks ?? [])];
|
|
1387
|
+
if (!sinks.some((sink, index) => resolveSinkName(sink, index).trim().toLowerCase() === "portal")) {
|
|
1388
|
+
sinks.push(new PortalReportingSink());
|
|
1389
|
+
}
|
|
1390
|
+
return this.mergeValues({ ReportingSinks: sinks });
|
|
1391
|
+
}
|
|
1381
1392
|
/**
|
|
1382
1393
|
* Registers runtime policies for the run.
|
|
1383
1394
|
* Use this when scenario selection or step execution should obey policy callbacks.
|
|
@@ -2118,6 +2129,9 @@ export class LoadStrikeRunner {
|
|
|
2118
2129
|
static WithReportingSinks(context, ...sinks) {
|
|
2119
2130
|
return context.WithReportingSinks(...sinks);
|
|
2120
2131
|
}
|
|
2132
|
+
static WithPortalReporting(context) {
|
|
2133
|
+
return context.WithPortalReporting();
|
|
2134
|
+
}
|
|
2121
2135
|
/**
|
|
2122
2136
|
* Registers runtime policies for the run.
|
|
2123
2137
|
* Use this when scenario selection or step execution should obey policy callbacks.
|
|
@@ -2346,6 +2360,29 @@ export class LoadStrikeRunner {
|
|
|
2346
2360
|
WithReportingInterval(intervalSeconds) {
|
|
2347
2361
|
return this.withReportingInterval(intervalSeconds);
|
|
2348
2362
|
}
|
|
2363
|
+
withReportingSinks(...sinks) {
|
|
2364
|
+
if (!sinks.length) {
|
|
2365
|
+
throw new Error("At least one reporting sink should be provided.");
|
|
2366
|
+
}
|
|
2367
|
+
if (sinks.some((sink) => sink == null)) {
|
|
2368
|
+
throw new Error("Reporting sink collection cannot contain null values.");
|
|
2369
|
+
}
|
|
2370
|
+
validateNamedReportingSinks(sinks);
|
|
2371
|
+
return this.configure({ reportingSinks: sinks });
|
|
2372
|
+
}
|
|
2373
|
+
WithReportingSinks(...sinks) {
|
|
2374
|
+
return this.withReportingSinks(...sinks);
|
|
2375
|
+
}
|
|
2376
|
+
withPortalReporting() {
|
|
2377
|
+
const sinks = [...(this.options.reportingSinks ?? [])];
|
|
2378
|
+
if (!sinks.some((sink, index) => resolveSinkName(sink, index).trim().toLowerCase() === "portal")) {
|
|
2379
|
+
sinks.push(new PortalReportingSink());
|
|
2380
|
+
}
|
|
2381
|
+
return this.configure({ reportingSinks: sinks });
|
|
2382
|
+
}
|
|
2383
|
+
WithPortalReporting() {
|
|
2384
|
+
return this.withPortalReporting();
|
|
2385
|
+
}
|
|
2349
2386
|
/**
|
|
2350
2387
|
* Sets the timeout for cluster command round-trips.
|
|
2351
2388
|
* Use this when distributed control messages need a tighter or looser deadline.
|
|
@@ -2519,6 +2556,7 @@ export class LoadStrikeRunner {
|
|
|
2519
2556
|
testInfo,
|
|
2520
2557
|
getNodeInfo: () => attachNodeInfoAliases({ ...nodeInfo })
|
|
2521
2558
|
};
|
|
2559
|
+
attachPortalReportingSession(sinkSession, sessionInfo, licenseClient, licenseSession);
|
|
2522
2560
|
attachSessionStartInfoAliases(sessionInfo);
|
|
2523
2561
|
nodeInfo.currentOperation = "Init";
|
|
2524
2562
|
for (const plugin of plugins) {
|
|
@@ -4052,10 +4090,23 @@ function attachSessionStartInfoAliases(session) {
|
|
|
4052
4090
|
attachAliasMap(session, {
|
|
4053
4091
|
StartedUtc: "startedUtc",
|
|
4054
4092
|
ScenarioNames: "scenarioNames",
|
|
4055
|
-
Scenarios: "scenarios"
|
|
4093
|
+
Scenarios: "scenarios",
|
|
4094
|
+
RunToken: "runToken",
|
|
4095
|
+
PortalReportingIngestUrl: "portalReportingIngestUrl"
|
|
4056
4096
|
});
|
|
4057
4097
|
return session;
|
|
4058
4098
|
}
|
|
4099
|
+
function attachPortalReportingSession(sinkSession, sessionInfo, licenseClient, licenseSession) {
|
|
4100
|
+
const runToken = stringValueOrDefault(licenseSession?.runToken, "").trim();
|
|
4101
|
+
if (!runToken || !licenseClient) {
|
|
4102
|
+
return;
|
|
4103
|
+
}
|
|
4104
|
+
const ingestUrl = licenseClient.portalReportingIngestUrl();
|
|
4105
|
+
sinkSession.runToken = runToken;
|
|
4106
|
+
sinkSession.portalReportingIngestUrl = ingestUrl;
|
|
4107
|
+
sessionInfo.runToken = runToken;
|
|
4108
|
+
sessionInfo.portalReportingIngestUrl = ingestUrl;
|
|
4109
|
+
}
|
|
4059
4110
|
function attachScenarioInitContextAliases(context) {
|
|
4060
4111
|
context.nodeInfo = attachNodeInfoAliases(context.nodeInfo);
|
|
4061
4112
|
context.testInfo = attachTestInfoAliases(context.testInfo);
|
package/dist/esm/sinks.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { LoadStrikePluginData as LoadStrikePluginDataModel, LoadStrikePluginDataTable as LoadStrikePluginDataTableModel } from "./runtime.js";
|
|
2
|
+
import { createHash } from "node:crypto";
|
|
2
3
|
import { Pool } from "pg";
|
|
3
4
|
const DEFAULT_INFLUX_CONFIGURATION_SECTION_PATH = "LoadStrike:ReportingSinks:InfluxDb";
|
|
4
5
|
const DEFAULT_GRAFANA_LOKI_CONFIGURATION_SECTION_PATH = "LoadStrike:ReportingSinks:GrafanaLoki";
|
|
@@ -372,6 +373,91 @@ export class CompositeReportingSink {
|
|
|
372
373
|
await this.stop();
|
|
373
374
|
}
|
|
374
375
|
}
|
|
376
|
+
export class PortalReportingSink {
|
|
377
|
+
constructor(options = {}) {
|
|
378
|
+
this.sinkName = "portal";
|
|
379
|
+
this.SinkName = "portal";
|
|
380
|
+
this.licenseFeature = "extensions.reporting_sinks.portal";
|
|
381
|
+
this.LicenseFeature = "extensions.reporting_sinks.portal";
|
|
382
|
+
this.baseContext = null;
|
|
383
|
+
this.session = null;
|
|
384
|
+
this.runToken = "";
|
|
385
|
+
this.ingestUrl = "";
|
|
386
|
+
const source = asRecord(options);
|
|
387
|
+
this.timeoutMs = resolveTimeoutMs(optionNumber(source, "timeoutSeconds", "TimeoutSeconds"), optionNumber(source, "timeoutMs", "TimeoutMs"));
|
|
388
|
+
this.fetchImpl = pickRecordValue(source, "fetchImpl", "FetchImpl") ?? fetch;
|
|
389
|
+
}
|
|
390
|
+
init(context, _infraConfig) {
|
|
391
|
+
this.baseContext = cloneBaseContext(context);
|
|
392
|
+
}
|
|
393
|
+
Init(context, infraConfig) {
|
|
394
|
+
this.init(context, infraConfig);
|
|
395
|
+
}
|
|
396
|
+
start(session) {
|
|
397
|
+
this.runToken = String(session.runToken ?? session.RunToken ?? "").trim();
|
|
398
|
+
this.ingestUrl = String(session.portalReportingIngestUrl ?? session.PortalReportingIngestUrl ?? "").trim();
|
|
399
|
+
if (!this.runToken || !this.ingestUrl) {
|
|
400
|
+
throw new Error("PortalReportingSink requires a managed portal reporting session.");
|
|
401
|
+
}
|
|
402
|
+
this.session = sinkSessionMetadataFromContext(this.getBaseContext(), session);
|
|
403
|
+
}
|
|
404
|
+
Start(session) {
|
|
405
|
+
this.start(session);
|
|
406
|
+
}
|
|
407
|
+
async saveRealtimeStats(scenarioStats) {
|
|
408
|
+
await this.persistEvents(createRealtimeStatsEvents(this.getSession(), scenarioStats));
|
|
409
|
+
}
|
|
410
|
+
async SaveRealtimeStats(scenarioStats) {
|
|
411
|
+
await this.saveRealtimeStats(scenarioStats);
|
|
412
|
+
}
|
|
413
|
+
async saveRealtimeMetrics(metrics) {
|
|
414
|
+
await this.persistEvents(createRealtimeMetricEvents(this.getSession(), metrics));
|
|
415
|
+
}
|
|
416
|
+
async SaveRealtimeMetrics(metrics) {
|
|
417
|
+
await this.saveRealtimeMetrics(metrics);
|
|
418
|
+
}
|
|
419
|
+
async saveRunResult(result) {
|
|
420
|
+
await this.persistEvents(createRunResultEvents(this.getSession(), result));
|
|
421
|
+
}
|
|
422
|
+
async SaveRunResult(result) {
|
|
423
|
+
await this.saveRunResult(result);
|
|
424
|
+
}
|
|
425
|
+
stop() {
|
|
426
|
+
this.session = null;
|
|
427
|
+
}
|
|
428
|
+
Stop() {
|
|
429
|
+
this.stop();
|
|
430
|
+
}
|
|
431
|
+
Dispose() {
|
|
432
|
+
this.baseContext = null;
|
|
433
|
+
this.stop();
|
|
434
|
+
}
|
|
435
|
+
getBaseContext() {
|
|
436
|
+
if (!this.baseContext) {
|
|
437
|
+
throw new Error(`${this.sinkName} has not been initialized.`);
|
|
438
|
+
}
|
|
439
|
+
return this.baseContext;
|
|
440
|
+
}
|
|
441
|
+
getSession() {
|
|
442
|
+
if (!this.session) {
|
|
443
|
+
throw new Error(`${this.sinkName} has not been started.`);
|
|
444
|
+
}
|
|
445
|
+
return this.session;
|
|
446
|
+
}
|
|
447
|
+
async persistEvents(events) {
|
|
448
|
+
if (!events.length) {
|
|
449
|
+
return;
|
|
450
|
+
}
|
|
451
|
+
await postWithTimeout(this.fetchImpl, this.ingestUrl, {
|
|
452
|
+
method: "POST",
|
|
453
|
+
headers: { "Content-Type": "application/json" },
|
|
454
|
+
body: JSON.stringify({
|
|
455
|
+
runToken: this.runToken,
|
|
456
|
+
events: events.map((event, index) => portalEventPayload(event, index))
|
|
457
|
+
})
|
|
458
|
+
}, this.timeoutMs, "PortalReportingSink");
|
|
459
|
+
}
|
|
460
|
+
}
|
|
375
461
|
export class InfluxDbReportingSink {
|
|
376
462
|
constructor(options = {}) {
|
|
377
463
|
this.sinkName = "influxdb";
|
|
@@ -1528,6 +1614,37 @@ function createReportingEvent(session, occurredUtc, eventType, scenarioName, ste
|
|
|
1528
1614
|
fields: eventFields
|
|
1529
1615
|
};
|
|
1530
1616
|
}
|
|
1617
|
+
function portalEventPayload(event, index) {
|
|
1618
|
+
return {
|
|
1619
|
+
eventId: portalEventId(event, index),
|
|
1620
|
+
runId: event.sessionId,
|
|
1621
|
+
eventType: event.eventType,
|
|
1622
|
+
occurredUtc: event.occurredUtc.toISOString(),
|
|
1623
|
+
sessionId: event.sessionId,
|
|
1624
|
+
testSuite: event.testSuite,
|
|
1625
|
+
testName: event.testName,
|
|
1626
|
+
clusterId: event.clusterId,
|
|
1627
|
+
nodeType: event.nodeType,
|
|
1628
|
+
machineName: event.machineName,
|
|
1629
|
+
scenarioName: event.scenarioName,
|
|
1630
|
+
stepName: event.stepName,
|
|
1631
|
+
tags: { ...event.tags },
|
|
1632
|
+
fields: deepCloneRecord(event.fields)
|
|
1633
|
+
};
|
|
1634
|
+
}
|
|
1635
|
+
function portalEventId(event, index) {
|
|
1636
|
+
const material = JSON.stringify({
|
|
1637
|
+
sessionId: event.sessionId,
|
|
1638
|
+
eventType: event.eventType,
|
|
1639
|
+
occurredUtc: event.occurredUtc.toISOString(),
|
|
1640
|
+
scenarioName: event.scenarioName ?? "",
|
|
1641
|
+
stepName: event.stepName ?? "",
|
|
1642
|
+
index,
|
|
1643
|
+
tags: event.tags,
|
|
1644
|
+
fields: event.fields
|
|
1645
|
+
});
|
|
1646
|
+
return `lsr_${createHash("sha256").update(material).digest("hex").slice(0, 40)}`;
|
|
1647
|
+
}
|
|
1531
1648
|
function addMeasurementFields(fields, prefix, measurement) {
|
|
1532
1649
|
const request = measurement?.request ?? { count: 0, percent: 0, rps: 0 };
|
|
1533
1650
|
const latency = measurement?.latency ?? {
|
|
@@ -2553,7 +2670,9 @@ function cloneSessionStartInfo(session) {
|
|
|
2553
2670
|
...cloneBaseContext(session),
|
|
2554
2671
|
startedUtc: session.startedUtc,
|
|
2555
2672
|
scenarioNames: [...session.scenarioNames],
|
|
2556
|
-
scenarios: session.scenarios.map((value) => ({ ...value }))
|
|
2673
|
+
scenarios: session.scenarios.map((value) => ({ ...value })),
|
|
2674
|
+
runToken: session.runToken,
|
|
2675
|
+
portalReportingIngestUrl: session.portalReportingIngestUrl
|
|
2557
2676
|
};
|
|
2558
2677
|
}
|
|
2559
2678
|
function cloneNodeInfo(nodeInfo) {
|
|
@@ -2655,23 +2774,7 @@ function runResultToNodeStats(result) {
|
|
|
2655
2774
|
disabledSinks: [...(result.disabledSinks ?? [])],
|
|
2656
2775
|
sinkErrors: (result.sinkErrors ?? []).map((value) => ({ ...value })),
|
|
2657
2776
|
reportFiles: [...(result.reportFiles ?? [])],
|
|
2658
|
-
logFiles: [...(result.logFiles ?? [])]
|
|
2659
|
-
findScenarioStats: (scenarioName) => result.scenarioStats.find((value) => value.scenarioName === scenarioName),
|
|
2660
|
-
getScenarioStats: (scenarioName) => {
|
|
2661
|
-
const scenario = result.scenarioStats.find((value) => value.scenarioName === scenarioName);
|
|
2662
|
-
if (!scenario) {
|
|
2663
|
-
throw new Error(`Scenario stats not found: ${scenarioName}`);
|
|
2664
|
-
}
|
|
2665
|
-
return scenario;
|
|
2666
|
-
},
|
|
2667
|
-
FindScenarioStats: (scenarioName) => result.scenarioStats.find((value) => value.scenarioName === scenarioName),
|
|
2668
|
-
GetScenarioStats: (scenarioName) => {
|
|
2669
|
-
const scenario = result.scenarioStats.find((value) => value.scenarioName === scenarioName);
|
|
2670
|
-
if (!scenario) {
|
|
2671
|
-
throw new Error(`Scenario stats not found: ${scenarioName}`);
|
|
2672
|
-
}
|
|
2673
|
-
return scenario;
|
|
2674
|
-
}
|
|
2777
|
+
logFiles: [...(result.logFiles ?? [])]
|
|
2675
2778
|
};
|
|
2676
2779
|
}
|
|
2677
2780
|
function deepCloneRecord(value) {
|
package/dist/types/index.d.ts
CHANGED
|
@@ -8,5 +8,5 @@ export { CorrelationStoreConfiguration, CrossPlatformTrackingRuntime, InMemoryCo
|
|
|
8
8
|
export type { CorrelationEntry, DestinationConsumeResult, GatheredRow, CorrelationStoreKind, CorrelationRuntimeOptions, CorrelationRuntimePlugin, CorrelationRuntimeStats, CorrelationStore, SourceProduceResult, TrackingFieldLocation, TrackingPayload } from "./correlation.js";
|
|
9
9
|
export { LOADSTRIKE_TRACE_ID_HEADER, LOADSTRIKE_TRACE_ID_TRACKING_FIELD, TrafficEndpointDefinition, HttpEndpointDefinition, KafkaEndpointDefinition, KafkaSaslOptions, RabbitMqEndpointDefinition, NatsEndpointDefinition, RedisStreamsEndpointDefinition, AzureEventHubsEndpointDefinition, SqsEndpointDefinition, DelegateStreamEndpointDefinition, PushDiffusionEndpointDefinition, HttpOAuth2ClientCredentialsOptions, HttpAuthOptions } from "./transports.js";
|
|
10
10
|
export type { EndpointAdapter, EndpointDefinition, EndpointDefinitionInput, EndpointKind, EndpointMode, DotNetDelegateEndpointOptions, DotNetEndpointDefinition, DotNetHttpAuthOptions, DotNetHttpEndpointOptions, DotNetHttpOAuth2ClientCredentialsOptions, HttpAuthMode, HttpAuthType, HttpRequestBodyType, HttpResponseSource, HttpTrackingPayloadSource, KafkaSaslMechanismType, KafkaSecurityProtocolType, HttpEndpointOptions, KafkaEndpointOptions, RabbitMqEndpointOptions, NatsEndpointOptions, RedisStreamsEndpointOptions, AzureEventHubsEndpointOptions, SqsEndpointOptions, PushDiffusionEndpointOptions, TrackingFieldSelectorInput, TrackingRunMode, TrafficEndpointKind, TrafficEndpointMode, ProducedMessageRequest, ProducedMessageResult, ConsumedMessage, DelegateConsumeAsync, DelegateConsumeStreamHandler, DelegateEndpointOptions } from "./transports.js";
|
|
11
|
-
export { DatadogReportingSink, DatadogReportingSinkOptions, GrafanaLokiReportingSink, GrafanaLokiReportingSinkOptions, InfluxDbReportingSink, InfluxDbReportingSinkOptions, OtelCollectorReportingSink, OtelCollectorReportingSinkOptions, SplunkReportingSink, SplunkReportingSinkOptions, TimescaleDbReportingSink, TimescaleDbReportingSinkOptions } from "./sinks.js";
|
|
12
|
-
export type { DatadogSinkOptions, GrafanaLokiSinkOptions, InfluxDbSinkOptions, OtelCollectorSinkOptions, SplunkSinkOptions, TimescaleDbSinkOptions } from "./sinks.js";
|
|
11
|
+
export { DatadogReportingSink, DatadogReportingSinkOptions, GrafanaLokiReportingSink, GrafanaLokiReportingSinkOptions, InfluxDbReportingSink, InfluxDbReportingSinkOptions, OtelCollectorReportingSink, OtelCollectorReportingSinkOptions, PortalReportingSink, SplunkReportingSink, SplunkReportingSinkOptions, TimescaleDbReportingSink, TimescaleDbReportingSinkOptions } from "./sinks.js";
|
|
12
|
+
export type { DatadogSinkOptions, GrafanaLokiSinkOptions, InfluxDbSinkOptions, OtelCollectorSinkOptions, PortalReportingSinkOptionsInput, SplunkSinkOptions, TimescaleDbSinkOptions } from "./sinks.js";
|
package/dist/types/local.d.ts
CHANGED
|
@@ -29,6 +29,7 @@ export declare class LoadStrikeLocalClient {
|
|
|
29
29
|
* Use this when the surrounding wrapper type makes this operation the clearest way to express your intent.
|
|
30
30
|
*/
|
|
31
31
|
constructor(options?: LoadStrikeLocalClientOptions);
|
|
32
|
+
portalReportingIngestUrl(): string;
|
|
32
33
|
run(request: LoadStrikeRunRequest): Promise<LoadStrikeRunResponse>;
|
|
33
34
|
acquireLicenseLease(request: LoadStrikeRunRequest): Promise<LicenseValidationSession>;
|
|
34
35
|
releaseLicenseLease(session: LicenseValidationSession, request: LoadStrikeRunRequest): Promise<void>;
|
package/dist/types/runtime.d.ts
CHANGED
|
@@ -558,6 +558,8 @@ export interface LoadStrikeSinkSession {
|
|
|
558
558
|
configPath?: string;
|
|
559
559
|
infraConfigPath?: string;
|
|
560
560
|
infraConfig?: Record<string, unknown>;
|
|
561
|
+
runToken?: string;
|
|
562
|
+
portalReportingIngestUrl?: string;
|
|
561
563
|
}
|
|
562
564
|
export interface LoadStrikeBaseContext {
|
|
563
565
|
logger: LoadStrikeLogger;
|
|
@@ -573,9 +575,13 @@ export interface LoadStrikeSessionStartInfo extends LoadStrikeBaseContext {
|
|
|
573
575
|
startedUtc: string;
|
|
574
576
|
scenarioNames: string[];
|
|
575
577
|
scenarios: LoadStrikeScenarioStartInfo[];
|
|
578
|
+
runToken?: string;
|
|
579
|
+
portalReportingIngestUrl?: string;
|
|
576
580
|
readonly StartedUtc?: string;
|
|
577
581
|
readonly ScenarioNames?: string[];
|
|
578
582
|
readonly Scenarios?: LoadStrikeScenarioStartInfo[];
|
|
583
|
+
readonly RunToken?: string;
|
|
584
|
+
readonly PortalReportingIngestUrl?: string;
|
|
579
585
|
}
|
|
580
586
|
type RequireAtLeastOne<T, Keys extends keyof T = keyof T> = Omit<T, Keys> & {
|
|
581
587
|
[Key in Keys]-?: Required<Pick<T, Key>> & Partial<Pick<T, Exclude<Keys, Key>>>;
|
|
@@ -1339,6 +1345,8 @@ export declare class LoadStrikeContext {
|
|
|
1339
1345
|
* Use this when run results must be pushed to external observability or storage systems.
|
|
1340
1346
|
*/
|
|
1341
1347
|
WithReportingSinks(...sinks: ILoadStrikeReportingSink[]): LoadStrikeContext;
|
|
1348
|
+
withPortalReporting(): LoadStrikeContext;
|
|
1349
|
+
WithPortalReporting(): LoadStrikeContext;
|
|
1342
1350
|
/**
|
|
1343
1351
|
* Registers runtime policies for the run.
|
|
1344
1352
|
* Use this when scenario selection or step execution should obey policy callbacks.
|
|
@@ -1790,6 +1798,7 @@ export declare class LoadStrikeRunner {
|
|
|
1790
1798
|
* Use this when run results must be pushed to external observability or storage systems.
|
|
1791
1799
|
*/
|
|
1792
1800
|
static WithReportingSinks(context: LoadStrikeContext, ...sinks: ILoadStrikeReportingSink[]): LoadStrikeContext;
|
|
1801
|
+
static WithPortalReporting(context: LoadStrikeContext): LoadStrikeContext;
|
|
1793
1802
|
/**
|
|
1794
1803
|
* Registers runtime policies for the run.
|
|
1795
1804
|
* Use this when scenario selection or step execution should obey policy callbacks.
|
|
@@ -1924,6 +1933,10 @@ export declare class LoadStrikeRunner {
|
|
|
1924
1933
|
* Use this when sinks or dashboards should receive updates at a controlled interval.
|
|
1925
1934
|
*/
|
|
1926
1935
|
WithReportingInterval(intervalSeconds: number): LoadStrikeRunner;
|
|
1936
|
+
withReportingSinks(...sinks: ILoadStrikeReportingSink[]): LoadStrikeRunner;
|
|
1937
|
+
WithReportingSinks(...sinks: ILoadStrikeReportingSink[]): LoadStrikeRunner;
|
|
1938
|
+
withPortalReporting(): LoadStrikeRunner;
|
|
1939
|
+
WithPortalReporting(): LoadStrikeRunner;
|
|
1927
1940
|
/**
|
|
1928
1941
|
* Sets the timeout for cluster command round-trips.
|
|
1929
1942
|
* Use this when distributed control messages need a tighter or looser deadline.
|
package/dist/types/sinks.d.ts
CHANGED
|
@@ -21,10 +21,6 @@ interface LoadStrikeNodeStats {
|
|
|
21
21
|
sinkErrors: LoadStrikeSinkError[];
|
|
22
22
|
reportFiles: string[];
|
|
23
23
|
logFiles: string[];
|
|
24
|
-
findScenarioStats: (scenarioName: string) => LoadStrikeScenarioStats | undefined;
|
|
25
|
-
getScenarioStats: (scenarioName: string) => LoadStrikeScenarioStats;
|
|
26
|
-
FindScenarioStats: (scenarioName: string) => LoadStrikeScenarioStats | undefined;
|
|
27
|
-
GetScenarioStats: (scenarioName: string) => LoadStrikeScenarioStats;
|
|
28
24
|
}
|
|
29
25
|
type SinkFetch = (input: string, init?: RequestInit) => Promise<Response>;
|
|
30
26
|
interface ReportingSinkEvent {
|
|
@@ -282,6 +278,14 @@ export interface OtelCollectorSinkOptionsInput {
|
|
|
282
278
|
FetchImpl?: SinkFetch;
|
|
283
279
|
fetchImpl?: SinkFetch;
|
|
284
280
|
}
|
|
281
|
+
export interface PortalReportingSinkOptionsInput {
|
|
282
|
+
TimeoutSeconds?: number;
|
|
283
|
+
timeoutSeconds?: number;
|
|
284
|
+
TimeoutMs?: number;
|
|
285
|
+
timeoutMs?: number;
|
|
286
|
+
FetchImpl?: SinkFetch;
|
|
287
|
+
fetchImpl?: SinkFetch;
|
|
288
|
+
}
|
|
285
289
|
export declare class InfluxDbReportingSinkOptions {
|
|
286
290
|
ConfigurationSectionPath: string;
|
|
287
291
|
BaseUrl: string;
|
|
@@ -439,6 +443,35 @@ export declare class CompositeReportingSink implements LoadStrikeReportingSink {
|
|
|
439
443
|
stop(): Promise<void>;
|
|
440
444
|
Stop(): Promise<void>;
|
|
441
445
|
}
|
|
446
|
+
export declare class PortalReportingSink implements LoadStrikeReportingSink {
|
|
447
|
+
readonly sinkName = "portal";
|
|
448
|
+
readonly SinkName = "portal";
|
|
449
|
+
readonly licenseFeature = "extensions.reporting_sinks.portal";
|
|
450
|
+
readonly LicenseFeature = "extensions.reporting_sinks.portal";
|
|
451
|
+
private readonly fetchImpl;
|
|
452
|
+
private readonly timeoutMs;
|
|
453
|
+
private baseContext;
|
|
454
|
+
private session;
|
|
455
|
+
private runToken;
|
|
456
|
+
private ingestUrl;
|
|
457
|
+
constructor(options?: PortalReportingSinkOptionsInput);
|
|
458
|
+
init(context: LoadStrikeBaseContext, _infraConfig: Record<string, unknown>): void;
|
|
459
|
+
Init(context: LoadStrikeBaseContext, infraConfig: Record<string, unknown>): void;
|
|
460
|
+
start(session: LoadStrikeSessionStartInfo): void;
|
|
461
|
+
Start(session: LoadStrikeSessionStartInfo): void;
|
|
462
|
+
saveRealtimeStats(scenarioStats: LoadStrikeScenarioStats[]): Promise<void>;
|
|
463
|
+
SaveRealtimeStats(scenarioStats: LoadStrikeScenarioStats[]): Promise<void>;
|
|
464
|
+
saveRealtimeMetrics(metrics: LoadStrikeMetricStats): Promise<void>;
|
|
465
|
+
SaveRealtimeMetrics(metrics: LoadStrikeMetricStats): Promise<void>;
|
|
466
|
+
saveRunResult(result: LoadStrikeRunResult): Promise<void>;
|
|
467
|
+
SaveRunResult(result: LoadStrikeRunResult): Promise<void>;
|
|
468
|
+
stop(): void;
|
|
469
|
+
Stop(): void;
|
|
470
|
+
Dispose(): void;
|
|
471
|
+
private getBaseContext;
|
|
472
|
+
private getSession;
|
|
473
|
+
private persistEvents;
|
|
474
|
+
}
|
|
442
475
|
export declare class InfluxDbReportingSink implements LoadStrikeReportingSink {
|
|
443
476
|
readonly sinkName = "influxdb";
|
|
444
477
|
readonly SinkName = "influxdb";
|
package/package.json
CHANGED