@oneuptime/common 12.0.34 → 13.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Models/DatabaseModels/GlobalConfig.ts +12 -12
- package/Models/DatabaseModels/InventoryItem.ts +44 -1
- package/Models/DatabaseModels/NetworkDevice.ts +126 -0
- package/Server/EnvironmentConfig.ts +47 -16
- package/Server/Infrastructure/Postgres/SchemaMigrations/1791700000000-AddMacAddressToNetworkDevice.ts +25 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +2 -0
- package/Server/Infrastructure/Redis.ts +8 -8
- package/Server/Infrastructure/Status.ts +10 -4
- package/Server/Services/DatabaseService.ts +65 -13
- package/Server/Services/InventoryItemService.ts +31 -1
- package/Server/Services/MonitorTemplateService.ts +140 -19
- package/Server/Services/NetworkDeviceAutoImportRuleEngineService.ts +349 -41
- package/Server/Services/NetworkDeviceDiscoveryScanService.ts +87 -2
- package/Server/Services/NetworkDeviceService.ts +69 -0
- package/Server/Services/UserNotificationRuleService.ts +76 -25
- package/Server/Types/Database/Permissions/ReadPermission.ts +45 -5
- package/Server/Types/Database/QueryUtil.ts +56 -0
- package/Server/Types/Markdown.ts +93 -1
- package/Server/Utils/Dashboard/PublicDashboardResourceListPolicy.ts +82 -17
- package/Server/Utils/EmailRollup/EmailRollupFlushRunner.ts +10 -1
- package/Server/Utils/EmailRollup/EmailRollupRenderer.ts +2 -2
- package/Server/Utils/Monitor/Criteria/CompareCriteria.ts +82 -35
- package/Server/Utils/Monitor/Criteria/MetricMonitorCriteria.ts +31 -5
- package/Server/Utils/Monitor/MonitorCriteriaEvaluator.ts +202 -37
- package/Server/Utils/Monitor/MonitorCriteriaExpectationBuilder.ts +82 -9
- package/Server/Utils/Monitor/MonitorCriteriaMessageBuilder.ts +16 -7
- package/Server/Utils/Monitor/MonitorCriteriaMessageFormatter.ts +29 -17
- package/Server/Utils/Monitor/MonitorCriteriaObservationBuilder.ts +107 -48
- package/Server/Utils/Monitor/NetworkDeviceMacLearningUtil.ts +158 -0
- package/Server/Utils/Monitor/NetworkInventoryUtil.ts +27 -0
- package/Server/Utils/Telemetry/EntityRegistry.ts +11 -1
- package/Server/Utils/Telemetry/TelemetryEntity.ts +83 -9
- package/Tests/App/Dashboard/AddNeighborToMonitoringModal.test.tsx +32 -0
- package/Tests/App/Dashboard/AdoptedDeviceDrawer.test.tsx +374 -0
- package/Tests/App/Dashboard/DashboardLabelVariables.test.tsx +580 -0
- package/Tests/App/Dashboard/DashboardMonitorLabelVariable.test.tsx +438 -0
- package/Tests/App/Dashboard/DashboardVariableAllContract.test.tsx +5 -2
- package/Tests/App/Dashboard/DeviceAttachmentCard.test.tsx +273 -0
- package/Tests/App/Dashboard/DiscoveryReviewInventoryRefresh.test.tsx +505 -0
- package/Tests/App/Dashboard/EntityDetailPanel.test.tsx +163 -0
- package/Tests/App/Dashboard/InfrastructureExplorer.test.tsx +401 -0
- package/Tests/App/Dashboard/InfrastructureGraph.test.tsx +232 -0
- package/Tests/App/Dashboard/InventoryItems.test.tsx +201 -0
- package/Tests/App/Dashboard/InventoryTypeAndStatusFacets.test.tsx +798 -0
- package/Tests/App/Dashboard/NetworkTopologyLiveView.test.tsx +320 -0
- package/Tests/App/Dashboard/NetworkTopologyToolbar.test.tsx +275 -0
- package/Tests/App/Dashboard/OnCallCalendarFeedEmptyState.test.tsx +975 -0
- package/Tests/App/Dashboard/OnCallCalendarFeedPlanGate.test.tsx +63 -0
- package/Tests/App/Dashboard/ServiceMapGraph.test.tsx +626 -0
- package/Tests/App/Dashboard/TopologyDataLoading.test.tsx +348 -0
- package/Tests/App/Dashboard/TopologyPageNavigation.test.tsx +331 -0
- package/Tests/App/Dashboard/UserSettingsEmailPreferences.test.tsx +603 -0
- package/Tests/App/Dashboard/UserSettingsNotificationSettings.test.tsx +324 -0
- package/Tests/App/PublicDashboard/DashboardVariableSelector.test.tsx +13 -4
- package/Tests/App/StatusPage/StatusPageOidcOrigin.test.tsx +223 -0
- package/Tests/Models/InventoryItemStatus.test.ts +147 -0
- package/Tests/Models/NetworkDeviceMacAddressColumn.test.ts +294 -0
- package/Tests/Server/API/DashboardPublicResourceListAPI.test.ts +129 -0
- package/Tests/Server/EnvironmentConfigValkey.test.ts +227 -0
- package/Tests/Server/Infrastructure/Postgres/AddMacAddressToNetworkDeviceMigration.test.ts +365 -0
- package/Tests/Server/Infrastructure/Postgres/CustomFieldValueMappingMigration.test.ts +62 -23
- package/Tests/Server/Infrastructure/ValkeyDeploymentConfig.test.ts +265 -0
- package/Tests/Server/Middleware/HttpMetricsMiddleware.test.ts +382 -0
- package/Tests/Server/Middleware/SCIMAuthorization.test.ts +525 -0
- package/Tests/Server/Services/DatabaseServiceAggregateBy.test.ts +291 -56
- package/Tests/Server/Services/DatabaseServiceSortTiebreaker.test.ts +151 -0
- package/Tests/Server/Services/InventoryItemManualCreate.test.ts +105 -0
- package/Tests/Server/Services/InventoryItemPromotionGate.test.ts +178 -0
- package/Tests/Server/Services/MonitorTemplateServiceCustomFieldSync.test.ts +502 -0
- package/Tests/Server/Services/NetworkDeviceAutoImportRuleEngineService.test.ts +1133 -81
- package/Tests/Server/Services/NetworkDeviceDiscoveryScanRegistration.test.ts +520 -0
- package/Tests/Server/Services/NetworkDeviceMacAddressNormalization.test.ts +572 -0
- package/Tests/Server/Types/Database/InventoryStatusPostgres.test.ts +368 -0
- package/Tests/Server/Types/Database/Permissions/ReadBlockPermission.test.ts +261 -14
- package/Tests/Server/Types/Database/QueryUtilIncludesAnyOfGroups.test.ts +169 -0
- package/Tests/Server/Types/Database/QueryUtilIncludesAnyOfGroupsPostgres.test.ts +297 -0
- package/Tests/Server/Types/Markdown.test.ts +194 -1
- package/Tests/Server/Types/Workflow/Components/IncomingWebhookUtils.test.ts +279 -0
- package/Tests/Server/Types/Workflow/Components/TextToJson.test.ts +212 -0
- package/Tests/Server/Utils/CustomField/CustomFieldMappingRegistry.test.ts +436 -0
- package/Tests/Server/Utils/Dashboard/PublicDashboardResourceListPolicy.test.ts +214 -0
- package/Tests/Server/Utils/EmailRollup/EmailRollupFlushRunnerBehaviour.test.ts +1 -1
- package/Tests/Server/Utils/EmailRollup/EmailRollupRenderer.test.ts +10 -3
- package/Tests/Server/Utils/EventLoop.test.ts +359 -0
- package/Tests/Server/Utils/JsonWebToken.test.ts +30 -0
- package/Tests/Server/Utils/Monitor/Criteria/CompareCriteria.test.ts +242 -0
- package/Tests/Server/Utils/Monitor/Criteria/CompareCriteriaAggregation.test.ts +13 -7
- package/Tests/Server/Utils/Monitor/Criteria/DatabaseMonitorCriteria.test.ts +29 -0
- package/Tests/Server/Utils/Monitor/Criteria/MetricMonitorCriteria.test.ts +30 -6
- package/Tests/Server/Utils/Monitor/Criteria/MetricMonitorCriteriaAnomalyUnits.test.ts +246 -0
- package/Tests/Server/Utils/Monitor/MonitorCriteriaEmailEvalLogAgreement.test.ts +280 -0
- package/Tests/Server/Utils/Monitor/MonitorCriteriaEvaluator.test.ts +224 -10
- package/Tests/Server/Utils/Monitor/MonitorCriteriaEvaluatorMetricUnits.test.ts +570 -0
- package/Tests/Server/Utils/Monitor/MonitorCriteriaExpectationBuilderUnits.test.ts +30 -5
- package/Tests/Server/Utils/Monitor/MonitorCriteriaMessageBuilderUnits.test.ts +68 -21
- package/Tests/Server/Utils/Monitor/MonitorCriteriaObservationBuilderUnits.test.ts +36 -19
- package/Tests/Server/Utils/Monitor/NetworkDeviceMacLearningUtil.test.ts +573 -0
- package/Tests/Server/Utils/Monitor/NetworkInventoryUtil.test.ts +317 -0
- package/Tests/Server/Utils/Telemetry/ContextSpanProcessor.test.ts +281 -0
- package/Tests/Server/Utils/Telemetry/InventoryDuplicateIdentity.test.ts +316 -0
- package/Tests/Server/Utils/Telemetry/TelemetryEntity.test.ts +111 -8
- package/Tests/Types/Database/IncludesAnyOfGroups.test.ts +106 -0
- package/Tests/Types/JSONFunctions.test.ts +40 -0
- package/Tests/Types/NetworkAutomation/AutoImportRunMerge.test.ts +235 -0
- package/Tests/Types/NetworkAutomation/RuleRunResult.test.ts +66 -0
- package/Tests/Types/NetworkAutomation/RuleRunResultDescribe.test.ts +309 -1
- package/Tests/Types/Telemetry/InventoryLiveness.test.ts +99 -0
- package/Tests/UI/Components/CustomFields/CustomFieldsDetail.test.tsx +160 -0
- package/Tests/UI/ReactRouterSingletonBuild.test.ts +133 -0
- package/Tests/UI/Rum/ReplayHeader.test.tsx +10 -2
- package/Tests/UI/Rum/ReplayPlayerChrome.test.tsx +514 -0
- package/Tests/UI/Rum/ReplayTimeFormat.test.ts +94 -0
- package/Tests/UI/Rum/ReplayUi.test.tsx +559 -0
- package/Tests/UI/Utils/Breadcrumb/fixtures/RealBreadcrumbTrails.ts +5 -0
- package/Tests/UI/Utils/Breadcrumb/fixtures/RealRoutePatterns.ts +1 -0
- package/Tests/Utils/Dashboard/Components/DashboardMonitorListComponent.test.ts +11 -1
- package/Tests/Utils/Dashboard/LabelVariable.test.ts +257 -0
- package/Tests/Utils/Dashboard/VariableUrlState.test.ts +144 -14
- package/Tests/Utils/MetricUnitUtil.test.ts +81 -0
- package/Tests/Utils/Monitor/DeviceMacLearningUtil.test.ts +497 -0
- package/Tests/Utils/Monitor/MetricValueFormatter.test.ts +546 -0
- package/Tests/Utils/Monitor/MonitorTemplateCustomFieldUtil.test.ts +218 -0
- package/Tests/Utils/Monitor/NetworkTopologyEndpointAdoption.test.ts +1755 -0
- package/Tests/Utils/NetworkAutomation/AutoImportRunChain.test.ts +320 -0
- package/Types/BaseDatabase/IncludesAnyOfGroups.ts +77 -0
- package/Types/Dashboard/DashboardComponents/ComponentArgument.ts +1 -0
- package/Types/Dashboard/DashboardComponents/DashboardMonitorListComponent.ts +1 -0
- package/Types/Dashboard/DashboardVariable.ts +8 -0
- package/Types/JSON.ts +4 -0
- package/Types/JSONFunctions.ts +16 -0
- package/Types/Monitor/SnmpMonitor/NetworkTopology.ts +13 -0
- package/Types/NetworkAutomation/RuleRunResult.ts +402 -13
- package/Types/SerializableObjectDictionary.ts +4 -0
- package/Types/Telemetry/InventoryLiveness.ts +56 -0
- package/UI/Components/CSVFileUpload/CSVFileUpload.tsx +9 -2
- package/UI/Components/CustomFields/CustomFieldsDetail.tsx +46 -21
- package/UI/Components/Dashboard/DashboardVariableControl.tsx +285 -0
- package/UI/esbuild-config.js +6 -0
- package/Utils/Dashboard/Components/DashboardMonitorListComponent.ts +12 -1
- package/Utils/Dashboard/LabelVariable.ts +152 -0
- package/Utils/Dashboard/VariableUrlState.ts +27 -5
- package/Utils/MetricUnitUtil.ts +34 -0
- package/Utils/Monitor/DeviceMacLearningUtil.ts +177 -0
- package/Utils/Monitor/MetricValueFormatter.ts +342 -0
- package/Utils/Monitor/MonitorTemplateCustomFieldUtil.ts +124 -0
- package/Utils/Monitor/NetworkDeviceMonitorTemplateUtil.ts +7 -2
- package/Utils/Monitor/NetworkTopologyUtil.ts +693 -0
- package/Utils/NetworkAutomation/AutoImportRunChain.ts +138 -0
- package/build/dist/Models/DatabaseModels/GlobalConfig.js +12 -12
- package/build/dist/Models/DatabaseModels/GlobalConfig.js.map +1 -1
- package/build/dist/Models/DatabaseModels/InventoryItem.js +34 -1
- package/build/dist/Models/DatabaseModels/InventoryItem.js.map +1 -1
- package/build/dist/Models/DatabaseModels/NetworkDevice.js +128 -0
- package/build/dist/Models/DatabaseModels/NetworkDevice.js.map +1 -1
- package/build/dist/Server/EnvironmentConfig.js +44 -12
- package/build/dist/Server/EnvironmentConfig.js.map +1 -1
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1791700000000-AddMacAddressToNetworkDevice.js +14 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1791700000000-AddMacAddressToNetworkDevice.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +2 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
- package/build/dist/Server/Infrastructure/Redis.js +8 -8
- package/build/dist/Server/Infrastructure/Redis.js.map +1 -1
- package/build/dist/Server/Infrastructure/Status.js +10 -4
- package/build/dist/Server/Infrastructure/Status.js.map +1 -1
- package/build/dist/Server/Services/DatabaseService.js +58 -13
- package/build/dist/Server/Services/DatabaseService.js.map +1 -1
- package/build/dist/Server/Services/InventoryItemService.js +28 -1
- package/build/dist/Server/Services/InventoryItemService.js.map +1 -1
- package/build/dist/Server/Services/MonitorTemplateService.js +116 -17
- package/build/dist/Server/Services/MonitorTemplateService.js.map +1 -1
- package/build/dist/Server/Services/NetworkDeviceAutoImportRuleEngineService.js +270 -37
- package/build/dist/Server/Services/NetworkDeviceAutoImportRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/NetworkDeviceDiscoveryScanService.js +65 -0
- package/build/dist/Server/Services/NetworkDeviceDiscoveryScanService.js.map +1 -1
- package/build/dist/Server/Services/NetworkDeviceService.js +54 -0
- package/build/dist/Server/Services/NetworkDeviceService.js.map +1 -1
- package/build/dist/Server/Services/UserNotificationRuleService.js +60 -25
- package/build/dist/Server/Services/UserNotificationRuleService.js.map +1 -1
- package/build/dist/Server/Types/Database/Permissions/ReadPermission.js +29 -4
- package/build/dist/Server/Types/Database/Permissions/ReadPermission.js.map +1 -1
- package/build/dist/Server/Types/Database/QueryUtil.js +36 -0
- package/build/dist/Server/Types/Database/QueryUtil.js.map +1 -1
- package/build/dist/Server/Types/Markdown.js +75 -0
- package/build/dist/Server/Types/Markdown.js.map +1 -1
- package/build/dist/Server/Utils/Dashboard/PublicDashboardResourceListPolicy.js +53 -18
- package/build/dist/Server/Utils/Dashboard/PublicDashboardResourceListPolicy.js.map +1 -1
- package/build/dist/Server/Utils/EmailRollup/EmailRollupFlushRunner.js +10 -1
- package/build/dist/Server/Utils/EmailRollup/EmailRollupFlushRunner.js.map +1 -1
- package/build/dist/Server/Utils/EmailRollup/EmailRollupRenderer.js +2 -2
- package/build/dist/Server/Utils/EmailRollup/EmailRollupRenderer.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/Criteria/CompareCriteria.js +58 -35
- package/build/dist/Server/Utils/Monitor/Criteria/CompareCriteria.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/Criteria/MetricMonitorCriteria.js +29 -5
- package/build/dist/Server/Utils/Monitor/Criteria/MetricMonitorCriteria.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorCriteriaEvaluator.js +166 -35
- package/build/dist/Server/Utils/Monitor/MonitorCriteriaEvaluator.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorCriteriaExpectationBuilder.js +58 -9
- package/build/dist/Server/Utils/Monitor/MonitorCriteriaExpectationBuilder.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorCriteriaMessageBuilder.js +9 -3
- package/build/dist/Server/Utils/Monitor/MonitorCriteriaMessageBuilder.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorCriteriaMessageFormatter.js +26 -12
- package/build/dist/Server/Utils/Monitor/MonitorCriteriaMessageFormatter.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorCriteriaObservationBuilder.js +74 -33
- package/build/dist/Server/Utils/Monitor/MonitorCriteriaObservationBuilder.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/NetworkDeviceMacLearningUtil.js +114 -0
- package/build/dist/Server/Utils/Monitor/NetworkDeviceMacLearningUtil.js.map +1 -0
- package/build/dist/Server/Utils/Monitor/NetworkInventoryUtil.js +25 -0
- package/build/dist/Server/Utils/Monitor/NetworkInventoryUtil.js.map +1 -1
- package/build/dist/Server/Utils/Telemetry/EntityRegistry.js +9 -1
- package/build/dist/Server/Utils/Telemetry/EntityRegistry.js.map +1 -1
- package/build/dist/Server/Utils/Telemetry/TelemetryEntity.js +70 -13
- package/build/dist/Server/Utils/Telemetry/TelemetryEntity.js.map +1 -1
- package/build/dist/Types/BaseDatabase/IncludesAnyOfGroups.js +54 -0
- package/build/dist/Types/BaseDatabase/IncludesAnyOfGroups.js.map +1 -0
- package/build/dist/Types/Dashboard/DashboardComponents/ComponentArgument.js +1 -0
- package/build/dist/Types/Dashboard/DashboardComponents/ComponentArgument.js.map +1 -1
- package/build/dist/Types/Dashboard/DashboardVariable.js +1 -0
- package/build/dist/Types/Dashboard/DashboardVariable.js.map +1 -1
- package/build/dist/Types/JSON.js +1 -0
- package/build/dist/Types/JSON.js.map +1 -1
- package/build/dist/Types/JSONFunctions.js +13 -0
- package/build/dist/Types/JSONFunctions.js.map +1 -1
- package/build/dist/Types/NetworkAutomation/RuleRunResult.js +291 -6
- package/build/dist/Types/NetworkAutomation/RuleRunResult.js.map +1 -1
- package/build/dist/Types/SerializableObjectDictionary.js +4 -0
- package/build/dist/Types/SerializableObjectDictionary.js.map +1 -1
- package/build/dist/Types/Telemetry/InventoryLiveness.js +37 -0
- package/build/dist/Types/Telemetry/InventoryLiveness.js.map +1 -0
- package/build/dist/UI/Components/CSVFileUpload/CSVFileUpload.js +7 -0
- package/build/dist/UI/Components/CSVFileUpload/CSVFileUpload.js.map +1 -1
- package/build/dist/UI/Components/CustomFields/CustomFieldsDetail.js +9 -2
- package/build/dist/UI/Components/CustomFields/CustomFieldsDetail.js.map +1 -1
- package/build/dist/UI/Components/Dashboard/DashboardVariableControl.js +137 -0
- package/build/dist/UI/Components/Dashboard/DashboardVariableControl.js.map +1 -0
- package/build/dist/Utils/Dashboard/Components/DashboardMonitorListComponent.js +9 -1
- package/build/dist/Utils/Dashboard/Components/DashboardMonitorListComponent.js.map +1 -1
- package/build/dist/Utils/Dashboard/LabelVariable.js +96 -0
- package/build/dist/Utils/Dashboard/LabelVariable.js.map +1 -0
- package/build/dist/Utils/Dashboard/VariableUrlState.js +19 -4
- package/build/dist/Utils/Dashboard/VariableUrlState.js.map +1 -1
- package/build/dist/Utils/MetricUnitUtil.js +26 -0
- package/build/dist/Utils/MetricUnitUtil.js.map +1 -1
- package/build/dist/Utils/Monitor/DeviceMacLearningUtil.js +112 -0
- package/build/dist/Utils/Monitor/DeviceMacLearningUtil.js.map +1 -0
- package/build/dist/Utils/Monitor/MetricValueFormatter.js +276 -0
- package/build/dist/Utils/Monitor/MetricValueFormatter.js.map +1 -0
- package/build/dist/Utils/Monitor/MonitorTemplateCustomFieldUtil.js +101 -0
- package/build/dist/Utils/Monitor/MonitorTemplateCustomFieldUtil.js.map +1 -0
- package/build/dist/Utils/Monitor/NetworkDeviceMonitorTemplateUtil.js +7 -2
- package/build/dist/Utils/Monitor/NetworkDeviceMonitorTemplateUtil.js.map +1 -1
- package/build/dist/Utils/Monitor/NetworkTopologyUtil.js +484 -0
- package/build/dist/Utils/Monitor/NetworkTopologyUtil.js.map +1 -1
- package/build/dist/Utils/NetworkAutomation/AutoImportRunChain.js +59 -0
- package/build/dist/Utils/NetworkAutomation/AutoImportRunChain.js.map +1 -0
- package/jest.config.json +2 -0
- package/package.json +1 -1
- package/test-setup.sh +9 -9
- package/tsconfig.json +51 -11
- package/Tests/App/Dashboard/NotificationEmailPreferences.test.tsx +0 -399
|
@@ -100,6 +100,11 @@ import MonitorStepPodmanMonitor from "../../../Types/Monitor/MonitorStepPodmanMo
|
|
|
100
100
|
import MonitorStepProxmoxMonitor from "../../../Types/Monitor/MonitorStepProxmoxMonitor";
|
|
101
101
|
import MonitorStepCephMonitor from "../../../Types/Monitor/MonitorStepCephMonitor";
|
|
102
102
|
import MonitorStepDockerSwarmMonitor from "../../../Types/Monitor/MonitorStepDockerSwarmMonitor";
|
|
103
|
+
import MetricValueFormatter from "../../../Utils/Monitor/MetricValueFormatter";
|
|
104
|
+
import { getKubernetesMetricByMetricName } from "../../../Types/Monitor/KubernetesMetricCatalog";
|
|
105
|
+
import { getProxmoxMetricByMetricName } from "../../../Types/Monitor/ProxmoxMetricCatalog";
|
|
106
|
+
import { getCephMetricByMetricName } from "../../../Types/Monitor/CephMetricCatalog";
|
|
107
|
+
import { getDockerSwarmMetricByMetricName } from "../../../Types/Monitor/DockerSwarmMetricCatalog";
|
|
103
108
|
|
|
104
109
|
/**
|
|
105
110
|
* A cross-signal deep link into a telemetry explorer, plus the scope
|
|
@@ -1433,13 +1438,28 @@ ${contextBlock}
|
|
|
1433
1438
|
return null;
|
|
1434
1439
|
}
|
|
1435
1440
|
|
|
1441
|
+
const unitHeuristicMetricName: string | undefined =
|
|
1442
|
+
MonitorCriteriaEvaluator.metricNameForUnitHeuristics({
|
|
1443
|
+
metricName: ctx.metricName,
|
|
1444
|
+
isFormula: ctx.isFormula,
|
|
1445
|
+
});
|
|
1446
|
+
|
|
1436
1447
|
const lines: Array<string> = [];
|
|
1437
1448
|
lines.push(`- Metric: \`${ctx.metricName}\``);
|
|
1438
1449
|
if (ctx.alias) {
|
|
1439
1450
|
lines.push(`- Alias: \`${ctx.alias}\``);
|
|
1440
1451
|
}
|
|
1441
|
-
|
|
1442
|
-
|
|
1452
|
+
/*
|
|
1453
|
+
* Spell the unit out — "Bytes", not the UCUM "By" the exporter wrote —
|
|
1454
|
+
* and drop the line entirely for units that name no dimension, so a
|
|
1455
|
+
* ratio metric no longer reports the bare "Unit: 1".
|
|
1456
|
+
*/
|
|
1457
|
+
const readableUnit: string | null = MetricValueFormatter.getReadableUnit(
|
|
1458
|
+
ctx.unit,
|
|
1459
|
+
unitHeuristicMetricName,
|
|
1460
|
+
);
|
|
1461
|
+
if (readableUnit) {
|
|
1462
|
+
lines.push(`- Unit: ${readableUnit}`);
|
|
1443
1463
|
}
|
|
1444
1464
|
if (ctx.aggregationType) {
|
|
1445
1465
|
lines.push(`- Aggregation: ${ctx.aggregationType}`);
|
|
@@ -1459,8 +1479,16 @@ ${contextBlock}
|
|
|
1459
1479
|
if (ctx.components && ctx.components.length > 0) {
|
|
1460
1480
|
const componentLines: Array<string> = ctx.components.map(
|
|
1461
1481
|
(component: MetricComponent) => {
|
|
1462
|
-
const
|
|
1463
|
-
|
|
1482
|
+
const componentUnit: string | null =
|
|
1483
|
+
MetricValueFormatter.getReadableUnit(
|
|
1484
|
+
component.unit,
|
|
1485
|
+
MonitorCriteriaEvaluator.metricNameForUnitHeuristics({
|
|
1486
|
+
metricName: component.name,
|
|
1487
|
+
isFormula: component.isFormula,
|
|
1488
|
+
}),
|
|
1489
|
+
);
|
|
1490
|
+
const unitSuffix: string = componentUnit
|
|
1491
|
+
? ` — unit: ${componentUnit}`
|
|
1464
1492
|
: "";
|
|
1465
1493
|
const typeSuffix: string = component.isFormula ? " (formula)" : "";
|
|
1466
1494
|
return ` - \`${component.alias}\` = \`${component.name}\`${typeSuffix}${unitSuffix}`;
|
|
@@ -1504,6 +1532,7 @@ ${contextBlock}
|
|
|
1504
1532
|
totalSamples: ctx.totalSamplesInWindow,
|
|
1505
1533
|
unit: ctx.unit,
|
|
1506
1534
|
metricName: ctx.metricName,
|
|
1535
|
+
unitHeuristicMetricName: unitHeuristicMetricName,
|
|
1507
1536
|
alias: ctx.alias,
|
|
1508
1537
|
components: ctx.components || [],
|
|
1509
1538
|
})}`,
|
|
@@ -1575,6 +1604,11 @@ ${contextBlock}
|
|
|
1575
1604
|
totalSamples?: number | undefined;
|
|
1576
1605
|
unit: string | null;
|
|
1577
1606
|
metricName: string;
|
|
1607
|
+
/**
|
|
1608
|
+
* The metric name to reason about, or undefined for a formula.
|
|
1609
|
+
* See MonitorCriteriaEvaluator.metricNameForUnitHeuristics.
|
|
1610
|
+
*/
|
|
1611
|
+
unitHeuristicMetricName: string | undefined;
|
|
1578
1612
|
alias: string;
|
|
1579
1613
|
components: Array<MetricComponent>;
|
|
1580
1614
|
}): string {
|
|
@@ -1628,17 +1662,20 @@ ${contextBlock}
|
|
|
1628
1662
|
"Value",
|
|
1629
1663
|
];
|
|
1630
1664
|
|
|
1665
|
+
/*
|
|
1666
|
+
* The component columns carry no unit in their header any more. Each
|
|
1667
|
+
* cell now names the unit it actually landed on, and auto-scaling
|
|
1668
|
+
* means neighbouring rows can land on different ones — a header that
|
|
1669
|
+
* read "a (By)" over cells reading "900 KB" and "1.2 MB" states a
|
|
1670
|
+
* unit that neither row uses. The configured unit is not lost: the
|
|
1671
|
+
* Components bullet list above the table still records it.
|
|
1672
|
+
*/
|
|
1631
1673
|
for (const component of input.components) {
|
|
1632
|
-
|
|
1633
|
-
? `${component.alias} (${component.unit})`
|
|
1634
|
-
: component.alias;
|
|
1635
|
-
headerCells.push(label);
|
|
1674
|
+
headerCells.push(component.alias);
|
|
1636
1675
|
}
|
|
1637
1676
|
|
|
1638
1677
|
headerCells.push(...attrKeys);
|
|
1639
1678
|
|
|
1640
|
-
const unitSuffix: string = input.unit ? ` ${input.unit}` : "";
|
|
1641
|
-
|
|
1642
1679
|
const headerRow: string = `| ${headerCells.join(" | ")} |`;
|
|
1643
1680
|
const dividerRow: string = `| ${headerCells
|
|
1644
1681
|
.map(() => {
|
|
@@ -1658,7 +1695,11 @@ ${contextBlock}
|
|
|
1658
1695
|
`\`${timestampIso}\``,
|
|
1659
1696
|
metricCell,
|
|
1660
1697
|
aliasCell,
|
|
1661
|
-
|
|
1698
|
+
MetricValueFormatter.format({
|
|
1699
|
+
value: s.value,
|
|
1700
|
+
unit: input.unit,
|
|
1701
|
+
metricName: input.unitHeuristicMetricName,
|
|
1702
|
+
}),
|
|
1662
1703
|
];
|
|
1663
1704
|
|
|
1664
1705
|
for (const component of input.components) {
|
|
@@ -1668,11 +1709,24 @@ ${contextBlock}
|
|
|
1668
1709
|
return cv.alias === component.alias;
|
|
1669
1710
|
});
|
|
1670
1711
|
if (match && typeof match.value === "number") {
|
|
1671
|
-
|
|
1672
|
-
|
|
1673
|
-
|
|
1712
|
+
/*
|
|
1713
|
+
* Each component keeps its OWN unit. Component values are
|
|
1714
|
+
* indexed off the per-query series and never go through the
|
|
1715
|
+
* sample→threshold-unit conversion the main Value column
|
|
1716
|
+
* does, so they are in the component's legendUnit — mixing
|
|
1717
|
+
* units across the row is deliberate, and is why every cell
|
|
1718
|
+
* has to say which one it is in.
|
|
1719
|
+
*/
|
|
1674
1720
|
cells.push(
|
|
1675
|
-
|
|
1721
|
+
MetricValueFormatter.format({
|
|
1722
|
+
value: match.value,
|
|
1723
|
+
unit: component.unit,
|
|
1724
|
+
metricName:
|
|
1725
|
+
MonitorCriteriaEvaluator.metricNameForUnitHeuristics({
|
|
1726
|
+
metricName: component.name,
|
|
1727
|
+
isFormula: component.isFormula,
|
|
1728
|
+
}),
|
|
1729
|
+
}),
|
|
1676
1730
|
);
|
|
1677
1731
|
} else {
|
|
1678
1732
|
cells.push("-");
|
|
@@ -1722,16 +1776,6 @@ ${contextBlock}
|
|
|
1722
1776
|
return `${input.breachingCount} sample${input.breachingCount === 1 ? "" : "s"} breached the threshold.`;
|
|
1723
1777
|
}
|
|
1724
1778
|
|
|
1725
|
-
private static formatNumberForDisplay(value: number): string {
|
|
1726
|
-
if (!Number.isFinite(value)) {
|
|
1727
|
-
return String(value);
|
|
1728
|
-
}
|
|
1729
|
-
if (Number.isInteger(value)) {
|
|
1730
|
-
return value.toString();
|
|
1731
|
-
}
|
|
1732
|
-
return Number(value.toFixed(2)).toString();
|
|
1733
|
-
}
|
|
1734
|
-
|
|
1735
1779
|
private static buildMetricExplorerDeepLink(input: {
|
|
1736
1780
|
monitor: Monitor;
|
|
1737
1781
|
ctx: MetricCriteriaContext;
|
|
@@ -1923,6 +1967,27 @@ ${contextBlock}
|
|
|
1923
1967
|
};
|
|
1924
1968
|
}
|
|
1925
1969
|
|
|
1970
|
+
/**
|
|
1971
|
+
* The metric name to hand a unit heuristic, or undefined when there
|
|
1972
|
+
* isn't one.
|
|
1973
|
+
*
|
|
1974
|
+
* `MetricCriteriaContext.metricName` and `MetricComponent.name` are the
|
|
1975
|
+
* FORMULA EXPRESSION when the criteria (or the component) targets a
|
|
1976
|
+
* formula — MetricMonitorCriteria.buildContext falls back to
|
|
1977
|
+
* `metricFormula`. The only thing a name is used for downstream is
|
|
1978
|
+
* ValueFormatter.isFractionMetric, which asks whether the name ends in
|
|
1979
|
+
* `.utilization` / `_ratio` / `_percent` and multiplies a "1"-unit value
|
|
1980
|
+
* by 100 when it does. A formula written as `a / b_ratio` ends in
|
|
1981
|
+
* `_ratio` and would silently be reported at 100× its real value, so a
|
|
1982
|
+
* formula gets no name at all.
|
|
1983
|
+
*/
|
|
1984
|
+
private static metricNameForUnitHeuristics(input: {
|
|
1985
|
+
metricName: string | undefined;
|
|
1986
|
+
isFormula: boolean | undefined;
|
|
1987
|
+
}): string | undefined {
|
|
1988
|
+
return input.isFormula ? undefined : input.metricName;
|
|
1989
|
+
}
|
|
1990
|
+
|
|
1926
1991
|
private static formatScopeDroppedHint(dropped: Array<string>): string {
|
|
1927
1992
|
if (dropped.length === 0) {
|
|
1928
1993
|
return "";
|
|
@@ -1931,6 +1996,61 @@ ${contextBlock}
|
|
|
1931
1996
|
return ` _(scope partially carried — not applied: ${dropped.join(", ")})_`;
|
|
1932
1997
|
}
|
|
1933
1998
|
|
|
1999
|
+
/**
|
|
2000
|
+
* The unit for a value in a per-platform "Affected Resources" table.
|
|
2001
|
+
*
|
|
2002
|
+
* These rows are NOT the same numbers as the criteria's breaching
|
|
2003
|
+
* samples: the worker collects them with a raw `MetricService.findBy`
|
|
2004
|
+
* scan and never runs them through MetricResultUnitConverter, so they
|
|
2005
|
+
* are in the metric's NATIVE unit while the criteria threshold was
|
|
2006
|
+
* compared in the user's chosen display unit. Labelling them with the
|
|
2007
|
+
* query's legendUnit would therefore attach a confidently wrong unit to
|
|
2008
|
+
* a correct number.
|
|
2009
|
+
*
|
|
2010
|
+
* The catalog is the right source precisely because it also declares
|
|
2011
|
+
* the native unit. It is the same lookup, on the same metric name, that
|
|
2012
|
+
* the worker already ran to resolve `metricFriendlyName`, so the unit
|
|
2013
|
+
* shown here can never disagree with the metric name shown beside it.
|
|
2014
|
+
*/
|
|
2015
|
+
private static getPlatformMetricUnit(input: {
|
|
2016
|
+
platform: "kubernetes" | "proxmox" | "dockerSwarm" | "ceph";
|
|
2017
|
+
metricName: string;
|
|
2018
|
+
}): string | undefined {
|
|
2019
|
+
switch (input.platform) {
|
|
2020
|
+
case "kubernetes":
|
|
2021
|
+
return getKubernetesMetricByMetricName(input.metricName)?.unit;
|
|
2022
|
+
case "proxmox":
|
|
2023
|
+
return getProxmoxMetricByMetricName(input.metricName)?.unit;
|
|
2024
|
+
case "dockerSwarm":
|
|
2025
|
+
return getDockerSwarmMetricByMetricName(input.metricName)?.unit;
|
|
2026
|
+
case "ceph":
|
|
2027
|
+
return getCephMetricByMetricName(input.metricName)?.unit;
|
|
2028
|
+
default:
|
|
2029
|
+
return undefined;
|
|
2030
|
+
}
|
|
2031
|
+
}
|
|
2032
|
+
|
|
2033
|
+
/**
|
|
2034
|
+
* Render one cell of a platform breakdown table's Value column.
|
|
2035
|
+
*
|
|
2036
|
+
* Bold, because that is how these tables have always drawn the value —
|
|
2037
|
+
* it is the one number in the row a reader scans for.
|
|
2038
|
+
*/
|
|
2039
|
+
private static formatPlatformResourceValue(input: {
|
|
2040
|
+
platform: "kubernetes" | "proxmox" | "dockerSwarm" | "ceph";
|
|
2041
|
+
metricName: string;
|
|
2042
|
+
value: number;
|
|
2043
|
+
}): string {
|
|
2044
|
+
return `**${MetricValueFormatter.format({
|
|
2045
|
+
value: input.value,
|
|
2046
|
+
unit: MonitorCriteriaEvaluator.getPlatformMetricUnit({
|
|
2047
|
+
platform: input.platform,
|
|
2048
|
+
metricName: input.metricName,
|
|
2049
|
+
}),
|
|
2050
|
+
metricName: input.metricName,
|
|
2051
|
+
})}**`;
|
|
2052
|
+
}
|
|
2053
|
+
|
|
1934
2054
|
private static async buildKubernetesRootCauseContext(input: {
|
|
1935
2055
|
dataToProcess: DataToProcess;
|
|
1936
2056
|
monitorStep: MonitorStep;
|
|
@@ -2071,7 +2191,13 @@ ${contextBlock}
|
|
|
2071
2191
|
cells.push(resource.nodeName ? `\`${resource.nodeName}\`` : "-");
|
|
2072
2192
|
}
|
|
2073
2193
|
|
|
2074
|
-
cells.push(
|
|
2194
|
+
cells.push(
|
|
2195
|
+
MonitorCriteriaEvaluator.formatPlatformResourceValue({
|
|
2196
|
+
platform: "kubernetes",
|
|
2197
|
+
metricName: breakdown.metricName,
|
|
2198
|
+
value: resource.metricValue,
|
|
2199
|
+
}),
|
|
2200
|
+
);
|
|
2075
2201
|
|
|
2076
2202
|
resourceLines.push(`| ${cells.join(" | ")} |`);
|
|
2077
2203
|
}
|
|
@@ -2478,7 +2604,13 @@ ${contextBlock}
|
|
|
2478
2604
|
: "-";
|
|
2479
2605
|
|
|
2480
2606
|
resourceLines.push(
|
|
2481
|
-
`| ${resourceCell} | ${typeCell} | ${nodeCell} |
|
|
2607
|
+
`| ${resourceCell} | ${typeCell} | ${nodeCell} | ${MonitorCriteriaEvaluator.formatPlatformResourceValue(
|
|
2608
|
+
{
|
|
2609
|
+
platform: "proxmox",
|
|
2610
|
+
metricName: breakdown.metricName,
|
|
2611
|
+
value: resource.metricValue,
|
|
2612
|
+
},
|
|
2613
|
+
)} |`,
|
|
2482
2614
|
);
|
|
2483
2615
|
}
|
|
2484
2616
|
|
|
@@ -2640,7 +2772,13 @@ ${contextBlock}
|
|
|
2640
2772
|
: "-";
|
|
2641
2773
|
|
|
2642
2774
|
resourceLines.push(
|
|
2643
|
-
`| ${taskCell} | ${serviceCell} | ${nodeCell} |
|
|
2775
|
+
`| ${taskCell} | ${serviceCell} | ${nodeCell} | ${MonitorCriteriaEvaluator.formatPlatformResourceValue(
|
|
2776
|
+
{
|
|
2777
|
+
platform: "dockerSwarm",
|
|
2778
|
+
metricName: breakdown.metricName,
|
|
2779
|
+
value: resource.metricValue,
|
|
2780
|
+
},
|
|
2781
|
+
)} |`,
|
|
2644
2782
|
);
|
|
2645
2783
|
}
|
|
2646
2784
|
|
|
@@ -2865,7 +3003,13 @@ ${contextBlock}
|
|
|
2865
3003
|
: "-";
|
|
2866
3004
|
|
|
2867
3005
|
resourceLines.push(
|
|
2868
|
-
`| ${daemonCell} | ${poolCell} | ${hostCell} |
|
|
3006
|
+
`| ${daemonCell} | ${poolCell} | ${hostCell} | ${MonitorCriteriaEvaluator.formatPlatformResourceValue(
|
|
3007
|
+
{
|
|
3008
|
+
platform: "ceph",
|
|
3009
|
+
metricName: breakdown.metricName,
|
|
3010
|
+
value: resource.metricValue,
|
|
3011
|
+
},
|
|
3012
|
+
)} |`,
|
|
2869
3013
|
);
|
|
2870
3014
|
}
|
|
2871
3015
|
|
|
@@ -2914,6 +3058,27 @@ ${contextBlock}
|
|
|
2914
3058
|
const metricName: string = breakdown.metricName;
|
|
2915
3059
|
const lines: Array<string> = [];
|
|
2916
3060
|
|
|
3061
|
+
/*
|
|
3062
|
+
* The top resource's value, in the unit the catalog says the metric
|
|
3063
|
+
* is actually reported in.
|
|
3064
|
+
*
|
|
3065
|
+
* The three "is at N%" sentences below used to hardcode that percent
|
|
3066
|
+
* sign. Two of the three metrics they fire for are not percentages at
|
|
3067
|
+
* all — k8s.node.memory.usage and k8s.node.filesystem.usage are
|
|
3068
|
+
* `bytes`, so a node holding 8 GiB reported "memory usage is at
|
|
3069
|
+
* 8589934592.0%" — and the third, k8s.node.cpu.utilization, is the
|
|
3070
|
+
* kubeletstats cores gauge that four other places in this repo warn
|
|
3071
|
+
* is misnamed, so 1.4 cores in use read as "1.4% CPU utilization".
|
|
3072
|
+
*/
|
|
3073
|
+
const topResourceValue: string = MetricValueFormatter.format({
|
|
3074
|
+
value: topResource.metricValue,
|
|
3075
|
+
unit: MonitorCriteriaEvaluator.getPlatformMetricUnit({
|
|
3076
|
+
platform: "kubernetes",
|
|
3077
|
+
metricName: metricName,
|
|
3078
|
+
}),
|
|
3079
|
+
metricName: metricName,
|
|
3080
|
+
});
|
|
3081
|
+
|
|
2917
3082
|
if (
|
|
2918
3083
|
metricName === "k8s.container.restarts" ||
|
|
2919
3084
|
metricName.includes("restart")
|
|
@@ -2923,7 +3088,7 @@ ${contextBlock}
|
|
|
2923
3088
|
);
|
|
2924
3089
|
if (topResource.containerName) {
|
|
2925
3090
|
lines.push(
|
|
2926
|
-
`The container \`${topResource.containerName}\` in pod \`${topResource.podName || "unknown"}\` has restarted **${
|
|
3091
|
+
`The container \`${topResource.containerName}\` in pod \`${topResource.podName || "unknown"}\` has restarted **${topResourceValue}** times.`,
|
|
2927
3092
|
);
|
|
2928
3093
|
}
|
|
2929
3094
|
lines.push(
|
|
@@ -2959,7 +3124,7 @@ ${contextBlock}
|
|
|
2959
3124
|
lines.push(`One or more nodes have transitioned to a NotReady state.`);
|
|
2960
3125
|
if (topResource.nodeName) {
|
|
2961
3126
|
lines.push(
|
|
2962
|
-
`Node \`${topResource.nodeName}\` is reporting NotReady (value: ${
|
|
3127
|
+
`Node \`${topResource.nodeName}\` is reporting NotReady (value: ${topResourceValue}).`,
|
|
2963
3128
|
);
|
|
2964
3129
|
}
|
|
2965
3130
|
lines.push(
|
|
@@ -2986,7 +3151,7 @@ ${contextBlock}
|
|
|
2986
3151
|
lines.push(`Node CPU utilization has exceeded the configured threshold.`);
|
|
2987
3152
|
if (topResource.nodeName) {
|
|
2988
3153
|
lines.push(
|
|
2989
|
-
`Node \`${topResource.nodeName}\` is at **${
|
|
3154
|
+
`Node \`${topResource.nodeName}\` is at **${topResourceValue}** CPU utilization.`,
|
|
2990
3155
|
);
|
|
2991
3156
|
}
|
|
2992
3157
|
lines.push(
|
|
@@ -3007,7 +3172,7 @@ ${contextBlock}
|
|
|
3007
3172
|
);
|
|
3008
3173
|
if (topResource.nodeName) {
|
|
3009
3174
|
lines.push(
|
|
3010
|
-
`Node \`${topResource.nodeName}\` memory usage is at **${
|
|
3175
|
+
`Node \`${topResource.nodeName}\` memory usage is at **${topResourceValue}**.`,
|
|
3011
3176
|
);
|
|
3012
3177
|
}
|
|
3013
3178
|
lines.push(
|
|
@@ -3025,7 +3190,7 @@ ${contextBlock}
|
|
|
3025
3190
|
);
|
|
3026
3191
|
if (topResource.workloadName) {
|
|
3027
3192
|
lines.push(
|
|
3028
|
-
`${topResource.workloadType || "Deployment"} \`${topResource.workloadName}\` has **${
|
|
3193
|
+
`${topResource.workloadType || "Deployment"} \`${topResource.workloadName}\` has **${topResourceValue}** unavailable replica(s).`,
|
|
3029
3194
|
);
|
|
3030
3195
|
}
|
|
3031
3196
|
lines.push(
|
|
@@ -3041,7 +3206,7 @@ ${contextBlock}
|
|
|
3041
3206
|
lines.push(`Kubernetes Job has failed pods.`);
|
|
3042
3207
|
if (topResource.workloadName) {
|
|
3043
3208
|
lines.push(
|
|
3044
|
-
`Job \`${topResource.workloadName}\` has **${
|
|
3209
|
+
`Job \`${topResource.workloadName}\` has **${topResourceValue}** failed pod(s).`,
|
|
3045
3210
|
);
|
|
3046
3211
|
}
|
|
3047
3212
|
lines.push(
|
|
@@ -3060,7 +3225,7 @@ ${contextBlock}
|
|
|
3060
3225
|
);
|
|
3061
3226
|
if (topResource.nodeName) {
|
|
3062
3227
|
lines.push(
|
|
3063
|
-
`Node \`${topResource.nodeName}\` filesystem usage is at **${
|
|
3228
|
+
`Node \`${topResource.nodeName}\` filesystem usage is at **${topResourceValue}**.`,
|
|
3064
3229
|
);
|
|
3065
3230
|
}
|
|
3066
3231
|
lines.push(
|
|
@@ -3076,7 +3241,7 @@ ${contextBlock}
|
|
|
3076
3241
|
lines.push(`DaemonSet has misscheduled or unavailable nodes.`);
|
|
3077
3242
|
if (topResource.workloadName) {
|
|
3078
3243
|
lines.push(
|
|
3079
|
-
`DaemonSet \`${topResource.workloadName}\` has **${
|
|
3244
|
+
`DaemonSet \`${topResource.workloadName}\` has **${topResourceValue}** misscheduled node(s).`,
|
|
3080
3245
|
);
|
|
3081
3246
|
}
|
|
3082
3247
|
lines.push(
|
|
@@ -2,10 +2,21 @@ import {
|
|
|
2
2
|
CriteriaFilter,
|
|
3
3
|
FilterType,
|
|
4
4
|
} from "../../../Types/Monitor/CriteriaFilter";
|
|
5
|
+
import MetricValueFormatter from "../../../Utils/Monitor/MetricValueFormatter";
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* How a criteria's values are displayed: the unit, and the metric name
|
|
9
|
+
* the formatter's fraction / epoch rules are keyed on.
|
|
10
|
+
*/
|
|
11
|
+
export interface CriteriaDisplayOptions {
|
|
12
|
+
unit?: string | undefined;
|
|
13
|
+
metricName?: string | undefined;
|
|
14
|
+
}
|
|
5
15
|
|
|
6
16
|
export default class MonitorCriteriaExpectationBuilder {
|
|
7
17
|
public static getCriteriaFilterDescription(
|
|
8
18
|
criteriaFilter: CriteriaFilter,
|
|
19
|
+
options?: CriteriaDisplayOptions,
|
|
9
20
|
): string {
|
|
10
21
|
const parts: Array<string> = [criteriaFilter.checkOn];
|
|
11
22
|
|
|
@@ -14,15 +25,51 @@ export default class MonitorCriteriaExpectationBuilder {
|
|
|
14
25
|
}
|
|
15
26
|
|
|
16
27
|
if (criteriaFilter.value !== undefined && criteriaFilter.value !== null) {
|
|
17
|
-
|
|
28
|
+
const formatted: string | number =
|
|
29
|
+
MonitorCriteriaExpectationBuilder.formatThreshold(
|
|
30
|
+
criteriaFilter.value,
|
|
31
|
+
options,
|
|
32
|
+
) ?? criteriaFilter.value;
|
|
33
|
+
|
|
34
|
+
parts.push(String(formatted));
|
|
18
35
|
}
|
|
19
36
|
|
|
20
37
|
return parts.join(" ").trim();
|
|
21
38
|
}
|
|
22
39
|
|
|
40
|
+
/*
|
|
41
|
+
* The threshold, rendered exactly as an observed value would be — or
|
|
42
|
+
* returned untouched when it cannot be.
|
|
43
|
+
*
|
|
44
|
+
* Untouched covers three cases, and each matters: no unit was resolved
|
|
45
|
+
* (every non-metric checkOn, whose unit lives in its CheckOn label), the
|
|
46
|
+
* threshold is a string (the Contains / StartsWith family, which must
|
|
47
|
+
* quote what the user typed), or it is not a finite number.
|
|
48
|
+
*/
|
|
49
|
+
private static formatThreshold(
|
|
50
|
+
value: string | number | undefined,
|
|
51
|
+
options?: CriteriaDisplayOptions,
|
|
52
|
+
): string | number | undefined {
|
|
53
|
+
if (!options?.unit) {
|
|
54
|
+
return value;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
const numeric: number = Number(value);
|
|
58
|
+
|
|
59
|
+
if (typeof value === "boolean" || !Number.isFinite(numeric)) {
|
|
60
|
+
return value;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
return MetricValueFormatter.format({
|
|
64
|
+
value: numeric,
|
|
65
|
+
unit: options.unit,
|
|
66
|
+
metricName: options.metricName,
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
|
|
23
70
|
public static describeCriteriaExpectation(
|
|
24
71
|
criteriaFilter: CriteriaFilter,
|
|
25
|
-
options?:
|
|
72
|
+
options?: CriteriaDisplayOptions,
|
|
26
73
|
): string | null {
|
|
27
74
|
if (!criteriaFilter.filterType) {
|
|
28
75
|
return null;
|
|
@@ -30,35 +77,61 @@ export default class MonitorCriteriaExpectationBuilder {
|
|
|
30
77
|
|
|
31
78
|
let expectation: string;
|
|
32
79
|
|
|
80
|
+
/*
|
|
81
|
+
* Render the threshold the way the observed value is rendered, so the
|
|
82
|
+
* two halves of one sentence cannot describe one quantity differently.
|
|
83
|
+
* Reformatting only the observation produced "recorded latest 1.07 GB
|
|
84
|
+
* (expected to be greater than 1000000000 By)".
|
|
85
|
+
*
|
|
86
|
+
* A NON-numeric threshold falls back to the previous text verbatim —
|
|
87
|
+
* `criteriaFilter.value` is `string | number | undefined`, and the
|
|
88
|
+
* string filter types below must keep quoting exactly what the user
|
|
89
|
+
* typed. So must a threshold with no unit: `formatThreshold` is only
|
|
90
|
+
* installed when a unit was resolved, which happens for the two metric
|
|
91
|
+
* checkOns and nothing else.
|
|
92
|
+
*/
|
|
33
93
|
const value: string | number | undefined = criteriaFilter.value;
|
|
34
94
|
|
|
95
|
+
/*
|
|
96
|
+
* The threshold as the six value-comparison cases below should print
|
|
97
|
+
* it, unit included. Only those six get it: the string comparisons
|
|
98
|
+
* quote what the user typed, and the heartbeat windows carry their own
|
|
99
|
+
* "minutes" — formatting their value produced "within 5 sec minutes".
|
|
100
|
+
*/
|
|
101
|
+
const comparedValue: string | number | undefined =
|
|
102
|
+
MonitorCriteriaExpectationBuilder.formatThreshold(value, options);
|
|
103
|
+
|
|
35
104
|
/*
|
|
36
105
|
* Suffix numeric-threshold comparisons with the metric's display unit
|
|
37
106
|
* (e.g. "greater than 5 sec") so the threshold reads in the same unit
|
|
38
107
|
* as the observed value. Only the value-comparison filter types below
|
|
39
108
|
* carry a numeric threshold — the others (empty, boolean, heartbeat
|
|
40
109
|
* windows, …) supply their own wording and get no suffix.
|
|
110
|
+
*
|
|
111
|
+
* When the value was formatted above it already carries its unit, so
|
|
112
|
+
* this suffix collapses to empty and the unit is not printed twice.
|
|
41
113
|
*/
|
|
42
|
-
const unitSuffix: string =
|
|
114
|
+
const unitSuffix: string =
|
|
115
|
+
options?.unit && comparedValue === value ? ` ${options.unit}` : "";
|
|
43
116
|
|
|
44
117
|
switch (criteriaFilter.filterType) {
|
|
45
118
|
case FilterType.GreaterThan:
|
|
46
|
-
expectation = `to be greater than ${
|
|
119
|
+
expectation = `to be greater than ${comparedValue}${unitSuffix}`;
|
|
47
120
|
break;
|
|
48
121
|
case FilterType.GreaterThanOrEqualTo:
|
|
49
|
-
expectation = `to be greater than or equal to ${
|
|
122
|
+
expectation = `to be greater than or equal to ${comparedValue}${unitSuffix}`;
|
|
50
123
|
break;
|
|
51
124
|
case FilterType.LessThan:
|
|
52
|
-
expectation = `to be less than ${
|
|
125
|
+
expectation = `to be less than ${comparedValue}${unitSuffix}`;
|
|
53
126
|
break;
|
|
54
127
|
case FilterType.LessThanOrEqualTo:
|
|
55
|
-
expectation = `to be less than or equal to ${
|
|
128
|
+
expectation = `to be less than or equal to ${comparedValue}${unitSuffix}`;
|
|
56
129
|
break;
|
|
57
130
|
case FilterType.EqualTo:
|
|
58
|
-
expectation = `to equal ${
|
|
131
|
+
expectation = `to equal ${comparedValue}${unitSuffix}`;
|
|
59
132
|
break;
|
|
60
133
|
case FilterType.NotEqualTo:
|
|
61
|
-
expectation = `to not equal ${
|
|
134
|
+
expectation = `to not equal ${comparedValue}${unitSuffix}`;
|
|
62
135
|
break;
|
|
63
136
|
case FilterType.Contains:
|
|
64
137
|
expectation = `to contain ${value}`;
|
|
@@ -59,17 +59,19 @@ export default class MonitorCriteriaMessageBuilder {
|
|
|
59
59
|
* the observed value — "recorded latest 0.06 sec (expected to be greater
|
|
60
60
|
* than 5 sec)" rather than the unitless "0.06 (expected ... 5)".
|
|
61
61
|
*/
|
|
62
|
-
const
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
62
|
+
const metricDisplay: {
|
|
63
|
+
unit: string | undefined;
|
|
64
|
+
metricName: string | undefined;
|
|
65
|
+
} = MonitorCriteriaObservationBuilder.getMetricValueDisplayContext({
|
|
66
|
+
criteriaFilter: input.criteriaFilter,
|
|
67
|
+
dataToProcess: input.dataToProcess,
|
|
68
|
+
monitorStep: input.monitorStep,
|
|
69
|
+
});
|
|
68
70
|
|
|
69
71
|
const expectation: string | null =
|
|
70
72
|
MonitorCriteriaExpectationBuilder.describeCriteriaExpectation(
|
|
71
73
|
input.criteriaFilter,
|
|
72
|
-
|
|
74
|
+
metricDisplay,
|
|
73
75
|
);
|
|
74
76
|
|
|
75
77
|
const observation: string | null =
|
|
@@ -89,9 +91,16 @@ export default class MonitorCriteriaMessageBuilder {
|
|
|
89
91
|
}
|
|
90
92
|
|
|
91
93
|
if (expectation) {
|
|
94
|
+
/*
|
|
95
|
+
* Both halves of this sentence quote the same threshold, so both
|
|
96
|
+
* must render it the same way — otherwise it reads "Metric Value
|
|
97
|
+
* greater than 1000000000 did not satisfy the configured condition
|
|
98
|
+
* (expected to be greater than 1 GB)".
|
|
99
|
+
*/
|
|
92
100
|
const description: string =
|
|
93
101
|
MonitorCriteriaExpectationBuilder.getCriteriaFilterDescription(
|
|
94
102
|
input.criteriaFilter,
|
|
103
|
+
metricDisplay,
|
|
95
104
|
);
|
|
96
105
|
|
|
97
106
|
return `${description} did not satisfy the configured condition (${expectation}).`;
|
|
@@ -136,9 +136,24 @@ export default class MonitorCriteriaMessageFormatter {
|
|
|
136
136
|
return null;
|
|
137
137
|
}
|
|
138
138
|
|
|
139
|
+
/**
|
|
140
|
+
* "latest 1.07 GB (min 900 KB, max 1.07 GB) across 3 data points".
|
|
141
|
+
*
|
|
142
|
+
* `format`, when supplied, renders ONE value — unit included — and is
|
|
143
|
+
* applied to latest, min and max independently. That independence is the
|
|
144
|
+
* point: auto-scaling can land min and max on different rungs of the
|
|
145
|
+
* ladder, which a single trailing unit suffix cannot express. It is the
|
|
146
|
+
* same reason CompareCriteria puts the unit on each number rather than on
|
|
147
|
+
* the sentence, and using the same callback in both places is what stops
|
|
148
|
+
* the evaluation log and the alert email describing one sample two ways.
|
|
149
|
+
*
|
|
150
|
+
* Without it the `unit` string is appended as before, so the caller that
|
|
151
|
+
* passes no unit at all (execution time) stays byte-identical.
|
|
152
|
+
*/
|
|
139
153
|
public static summarizeNumericSeries(
|
|
140
154
|
values: Array<number>,
|
|
141
155
|
unit?: string | undefined,
|
|
156
|
+
format?: ((value: number) => string) | undefined,
|
|
142
157
|
): string | null {
|
|
143
158
|
if (!values.length) {
|
|
144
159
|
return null;
|
|
@@ -156,29 +171,26 @@ export default class MonitorCriteriaMessageFormatter {
|
|
|
156
171
|
*/
|
|
157
172
|
const unitSuffix: string = unit ? ` ${unit}` : "";
|
|
158
173
|
|
|
159
|
-
const
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
}
|
|
174
|
+
const renderValue: (value: number) => string = (value: number): string => {
|
|
175
|
+
if (format) {
|
|
176
|
+
return format(value);
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
const formatted: string | null =
|
|
180
|
+
MonitorCriteriaMessageFormatter.formatNumber(value, {
|
|
181
|
+
maximumFractionDigits: 2,
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
return `${formatted ?? value}${unitSuffix}`;
|
|
185
|
+
};
|
|
163
186
|
|
|
164
|
-
let summary: string = `latest ${
|
|
187
|
+
let summary: string = `latest ${renderValue(latest)}`;
|
|
165
188
|
|
|
166
189
|
if (values.length > 1) {
|
|
167
190
|
const min: number = Math.min(...values);
|
|
168
191
|
const max: number = Math.max(...values);
|
|
169
192
|
|
|
170
|
-
|
|
171
|
-
MonitorCriteriaMessageFormatter.formatNumber(min, {
|
|
172
|
-
maximumFractionDigits: 2,
|
|
173
|
-
});
|
|
174
|
-
const maxFormatted: string | null =
|
|
175
|
-
MonitorCriteriaMessageFormatter.formatNumber(max, {
|
|
176
|
-
maximumFractionDigits: 2,
|
|
177
|
-
});
|
|
178
|
-
|
|
179
|
-
summary += ` (min ${minFormatted ?? min}${unitSuffix}, max ${
|
|
180
|
-
maxFormatted ?? max
|
|
181
|
-
}${unitSuffix})`;
|
|
193
|
+
summary += ` (min ${renderValue(min)}, max ${renderValue(max)})`;
|
|
182
194
|
}
|
|
183
195
|
|
|
184
196
|
summary += ` across ${values.length} data point${
|