@oneuptime/common 14.0.2 → 14.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (765) hide show
  1. package/Models/DatabaseModels/Alert.ts +55 -0
  2. package/Models/DatabaseModels/AlertFeed.ts +2 -0
  3. package/Models/DatabaseModels/DatabaseServer.ts +1650 -0
  4. package/Models/DatabaseModels/DatabaseServerEndpoint.ts +540 -0
  5. package/Models/DatabaseModels/DatabaseServerFeed.ts +625 -0
  6. package/Models/DatabaseModels/DatabaseServerLabelRule.ts +514 -0
  7. package/Models/DatabaseModels/DatabaseServerOwnerRule.ts +596 -0
  8. package/Models/DatabaseModels/DatabaseServerOwnerTeam.ts +491 -0
  9. package/Models/DatabaseModels/DatabaseServerOwnerUser.ts +490 -0
  10. package/Models/DatabaseModels/Incident.ts +55 -0
  11. package/Models/DatabaseModels/IncidentAlert.ts +540 -0
  12. package/Models/DatabaseModels/IncidentFeed.ts +2 -0
  13. package/Models/DatabaseModels/Index.ts +18 -0
  14. package/Models/DatabaseModels/NetworkDeviceDiscoveryScan.ts +26 -0
  15. package/Models/DatabaseModels/Project.ts +60 -0
  16. package/Models/DatabaseModels/RumApplication.ts +52 -1
  17. package/Models/DatabaseModels/ScheduledMaintenance.ts +55 -0
  18. package/Models/DatabaseModels/TelemetryException.ts +2 -0
  19. package/Models/DatabaseModels/UserProjectSsoConsent.ts +146 -0
  20. package/Server/Infrastructure/Postgres/SchemaMigrations/1794800000000-AddSessionReplaySameOriginTracePropagation.ts +28 -0
  21. package/Server/Infrastructure/Postgres/SchemaMigrations/1794900000000-AddIncidentAlert.ts +89 -0
  22. package/Server/Infrastructure/Postgres/SchemaMigrations/1795000000000-AddDatabaseServerTables.ts +673 -0
  23. package/Server/Infrastructure/Postgres/SchemaMigrations/1795100000000-AddUserProjectSsoConsent.ts +51 -0
  24. package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +8 -0
  25. package/Server/Middleware/MultipartFormData.ts +1 -1
  26. package/Server/Middleware/TelemetryIngest.ts +15 -8
  27. package/Server/Services/AlertReminderRuleService.ts +100 -24
  28. package/Server/Services/DatabaseServerEndpointService.ts +895 -0
  29. package/Server/Services/DatabaseServerFeedService.ts +128 -0
  30. package/Server/Services/DatabaseServerLabelRuleEngineService.ts +340 -0
  31. package/Server/Services/DatabaseServerLabelRuleService.ts +14 -0
  32. package/Server/Services/DatabaseServerOwnerRuleEngineService.ts +425 -0
  33. package/Server/Services/DatabaseServerOwnerRuleService.ts +14 -0
  34. package/Server/Services/DatabaseServerOwnerTeamService.ts +180 -0
  35. package/Server/Services/DatabaseServerOwnerUserService.ts +173 -0
  36. package/Server/Services/DatabaseServerService.ts +4546 -0
  37. package/Server/Services/DatabaseService.ts +14 -8
  38. package/Server/Services/DockerResourceService.ts +43 -2
  39. package/Server/Services/IncidentAlertService.ts +1811 -0
  40. package/Server/Services/IncidentReminderRuleService.ts +103 -23
  41. package/Server/Services/IncidentService.ts +210 -10
  42. package/Server/Services/IncidentStateTimelineService.ts +24 -0
  43. package/Server/Services/Index.ts +18 -0
  44. package/Server/Services/InventoryItemService.ts +113 -5
  45. package/Server/Services/IoTDeviceService.ts +145 -37
  46. package/Server/Services/OpenTelemetryIngestService.ts +19 -0
  47. package/Server/Services/PodmanResourceService.ts +43 -2
  48. package/Server/Services/ScheduledMaintenanceReminderRuleService.ts +107 -23
  49. package/Server/Services/ServiceService.ts +1 -1
  50. package/Server/Services/TelemetryUsageBillingService.ts +29 -2
  51. package/Server/Services/UserProjectSsoConsentService.ts +74 -0
  52. package/Server/Services/UserService.ts +14 -1
  53. package/Server/Types/Database/Permissions/OwnerTableRegistry.ts +18 -0
  54. package/Server/Types/Database/QueryHelper.ts +30 -1
  55. package/Server/Utils/AI/Toolbox/ResourceTools.ts +69 -1
  56. package/Server/Utils/Database/AffectedResourceRelations.ts +6 -0
  57. package/Server/Utils/Monitor/Criteria/MetricMonitorCriteria.ts +188 -6
  58. package/Server/Utils/Monitor/MonitorAlert.ts +28 -1
  59. package/Server/Utils/Monitor/MonitorCriteriaEvaluator.ts +2262 -755
  60. package/Server/Utils/Monitor/MonitorIncident.ts +28 -1
  61. package/Server/Utils/Monitor/MonitorMaintenanceSuppression.ts +268 -6
  62. package/Server/Utils/Monitor/MonitorResource.ts +47 -11
  63. package/Server/Utils/Monitor/MonitorResourceContext.ts +1 -0
  64. package/Server/Utils/Monitor/MonitorStepResourceIdentity.ts +239 -21
  65. package/Server/Utils/Monitor/PerSeriesResolutionRootCause.ts +43 -0
  66. package/Server/Utils/Monitor/SeriesResourceLabels.ts +291 -0
  67. package/Server/Utils/Monitor/SeriesResourceLinker.ts +111 -12
  68. package/Server/Utils/Rules/RuleRun/RuleRunRegistry.ts +25 -0
  69. package/Server/Utils/SessionReplay/SessionReplayGateCache.ts +24 -2
  70. package/Server/Utils/StartServer.ts +26 -6
  71. package/Server/Utils/TeamMember/ProjectLeaveResourceCleanup.ts +2 -0
  72. package/Server/Utils/Telemetry/DatabaseEndpointDiscovery.ts +688 -0
  73. package/Server/Utils/Telemetry/EntityRegistry.ts +5 -1
  74. package/Server/Utils/Telemetry/LogExceptionExtractor.ts +18 -1
  75. package/Server/Utils/Telemetry/ResourceEntityFilter.ts +175 -12
  76. package/Server/Utils/Telemetry/ResourceFacetResolver.ts +12 -0
  77. package/Server/Utils/Telemetry/ServiceDependencyDiscovery.ts +606 -36
  78. package/Server/Utils/Telemetry/Telemetry.ts +16 -0
  79. package/Server/Utils/Telemetry/TelemetryEntity.ts +22 -22
  80. package/Server/Utils/Telemetry/TelemetryIngestionKeyGuard.ts +16 -10
  81. package/Tests/App/Accounts/SignedInRedirect.test.tsx +241 -0
  82. package/Tests/App/AdminDashboard/AdminHeaderSmallScreens.test.tsx +221 -4
  83. package/Tests/App/Dashboard/AIInsightsResourcePageContext.test.ts +42 -0
  84. package/Tests/App/Dashboard/AffectedResourcesDisplay.test.tsx +100 -0
  85. package/Tests/App/Dashboard/AffectedResourcesPicker.test.tsx +86 -0
  86. package/Tests/App/Dashboard/AffectedResourcesPickerHiddenTypes.test.tsx +2 -0
  87. package/Tests/App/Dashboard/AffectedResourcesSummaryStep.test.tsx +19 -0
  88. package/Tests/App/Dashboard/BreadcrumbCoverage.test.tsx +14 -0
  89. package/Tests/App/Dashboard/BulkIncidentLinkActions.test.tsx +869 -0
  90. package/Tests/App/Dashboard/CephMetricTooltips.test.tsx +1777 -0
  91. package/Tests/App/Dashboard/CloudFleetSummary.test.ts +8 -0
  92. package/Tests/App/Dashboard/CloudMetricTooltips.test.tsx +887 -0
  93. package/Tests/App/Dashboard/ContainerHostMetricTooltips.test.tsx +1309 -0
  94. package/Tests/App/Dashboard/CorrelateFilterBuilder.test.tsx +26 -1
  95. package/Tests/App/Dashboard/DashboardAppSsoError.test.tsx +501 -0
  96. package/Tests/App/Dashboard/DashboardHeaderRequests.test.tsx +64 -1
  97. package/Tests/App/Dashboard/DashboardHeaderSmallScreens.test.tsx +178 -18
  98. package/Tests/App/Dashboard/DashboardMasterPageSsoRedirect.test.tsx +444 -0
  99. package/Tests/App/Dashboard/DashboardNavBarForeignHiddenRule.test.tsx +573 -0
  100. package/Tests/App/Dashboard/DatabaseChartAxes.test.tsx +431 -0
  101. package/Tests/App/Dashboard/DatabaseContainerDetailBadge.test.tsx +249 -0
  102. package/Tests/App/Dashboard/DatabaseDashboardE2EFixes.test.ts +681 -0
  103. package/Tests/App/Dashboard/DatabaseDocumentationMarkdown.test.ts +1801 -0
  104. package/Tests/App/Dashboard/DatabaseFleetSummaryRefresh.test.tsx +280 -0
  105. package/Tests/App/Dashboard/DatabaseFormHelpers.test.tsx +321 -0
  106. package/Tests/App/Dashboard/DatabaseMetricMonitorLink.test.tsx +795 -0
  107. package/Tests/App/Dashboard/DatabaseOverviewHeader.test.tsx +580 -0
  108. package/Tests/App/Dashboard/DatabaseRecommendationsEngineMetrics.test.ts +270 -0
  109. package/Tests/App/Dashboard/DatabaseServerComponents.test.tsx +1486 -0
  110. package/Tests/App/Dashboard/DatabaseServerEngineMetricsFilter.test.ts +223 -0
  111. package/Tests/App/Dashboard/DatabaseServerPresentation.test.ts +435 -0
  112. package/Tests/App/Dashboard/DatabaseServerSummary.test.ts +186 -0
  113. package/Tests/App/Dashboard/DatabaseServerTelemetryQueries.test.ts +1553 -0
  114. package/Tests/App/Dashboard/DatabaseTableTruncation.test.tsx +326 -0
  115. package/Tests/App/Dashboard/DatabaseTelemetryScope.test.ts +512 -0
  116. package/Tests/App/Dashboard/DatabaseTelemetryTabs.test.tsx +774 -0
  117. package/Tests/App/Dashboard/DatabaseViewLayout.test.tsx +233 -0
  118. package/Tests/App/Dashboard/DatabaseWorkloadBadge.test.tsx +972 -0
  119. package/Tests/App/Dashboard/DiscoveryReviewInventoryRefresh.test.tsx +5 -0
  120. package/Tests/App/Dashboard/DiscoveryReviewUnnamedHostHint.test.tsx +1061 -0
  121. package/Tests/App/Dashboard/DiscoveryScanLivePage.test.tsx +39 -0
  122. package/Tests/App/Dashboard/DockerSwarmClustersListTooltips.test.tsx +414 -0
  123. package/Tests/App/Dashboard/DockerSwarmMetricTooltips.test.ts +796 -0
  124. package/Tests/App/Dashboard/DockerSwarmOverviewTooltips.test.tsx +747 -0
  125. package/Tests/App/Dashboard/EventOverlayScope.test.ts +147 -0
  126. package/Tests/App/Dashboard/EventOverlayScopeHook.test.tsx +1 -0
  127. package/Tests/App/Dashboard/ExceptionMonitorEnvironmentFilter.test.tsx +38 -18
  128. package/Tests/App/Dashboard/HostDetailViewTooltips.test.tsx +725 -0
  129. package/Tests/App/Dashboard/HostListColumnTooltips.test.tsx +472 -0
  130. package/Tests/App/Dashboard/HostMetricTooltips.test.ts +709 -0
  131. package/Tests/App/Dashboard/HostOverviewTooltips.test.tsx +698 -0
  132. package/Tests/App/Dashboard/HostTooltipHarness.ts +124 -0
  133. package/Tests/App/Dashboard/HostsListTooltips.test.tsx +395 -0
  134. package/Tests/App/Dashboard/IncidentAlertLinkDialog.test.tsx +691 -0
  135. package/Tests/App/Dashboard/IncidentAlertLinkHelpers.test.ts +458 -0
  136. package/Tests/App/Dashboard/IncidentAlertLinkPages.test.tsx +828 -0
  137. package/Tests/App/Dashboard/IncidentAlertLinkSideMenus.test.tsx +231 -0
  138. package/Tests/App/Dashboard/IncidentCreateFromAlerts.test.tsx +689 -0
  139. package/Tests/App/Dashboard/IoTMetricTooltips.test.tsx +1123 -0
  140. package/Tests/App/Dashboard/KubernetesClusterMetricTooltips.test.ts +837 -0
  141. package/Tests/App/Dashboard/KubernetesClusterOverviewTooltips.test.tsx +699 -0
  142. package/Tests/App/Dashboard/KubernetesContainersTabTooltips.test.tsx +320 -0
  143. package/Tests/App/Dashboard/KubernetesCostTooltips.test.tsx +502 -0
  144. package/Tests/App/Dashboard/KubernetesInsightsTooltips.test.tsx +222 -0
  145. package/Tests/App/Dashboard/KubernetesResourceMetricTooltips.test.ts +561 -0
  146. package/Tests/App/Dashboard/KubernetesResourcePagesTooltips.test.tsx +1168 -0
  147. package/Tests/App/Dashboard/LinkIncidentAlertModal.test.tsx +154 -0
  148. package/Tests/App/Dashboard/LogsResourceFacetChips.test.tsx +1 -0
  149. package/Tests/App/Dashboard/MetricDescriptionRules.ts +170 -0
  150. package/Tests/App/Dashboard/MetricDescriptionsCatalog.test.ts +206 -0
  151. package/Tests/App/Dashboard/MetricDescriptionsConsistency.test.ts +275 -0
  152. package/Tests/App/Dashboard/MetricsViewerDrillDown.test.tsx +310 -0
  153. package/Tests/App/Dashboard/MetricsViewerEntityScopedRows.test.tsx +495 -0
  154. package/Tests/App/Dashboard/MonitorCreateFromMonitorBackedDevice.test.tsx +132 -1
  155. package/Tests/App/Dashboard/NavigationSearchKeywords.test.tsx +5 -0
  156. package/Tests/App/Dashboard/NetworkDeviceTooltips.test.tsx +852 -0
  157. package/Tests/App/Dashboard/NetworkDiagnosticsTooltips.test.tsx +556 -0
  158. package/Tests/App/Dashboard/NetworkMetricTooltips.test.ts +1348 -0
  159. package/Tests/App/Dashboard/NetworkSiteTooltips.test.tsx +679 -0
  160. package/Tests/App/Dashboard/ProductOrientation.test.tsx +4 -3
  161. package/Tests/App/Dashboard/ProxmoxMetricTooltips.test.ts +592 -0
  162. package/Tests/App/Dashboard/ProxmoxOverviewTooltips.test.tsx +1002 -0
  163. package/Tests/App/Dashboard/ProxmoxResourcePageTooltips.test.tsx +923 -0
  164. package/Tests/App/Dashboard/RecommendationsLoadedContext.test.tsx +349 -0
  165. package/Tests/App/Dashboard/ResourceArchiveSettings.test.tsx +62 -0
  166. package/Tests/App/Dashboard/ResourceFeedPageWiring.test.ts +8 -1
  167. package/Tests/App/Dashboard/ResourceFeedPagesFilterSort.test.tsx +14 -0
  168. package/Tests/App/Dashboard/ResourceOverviewTileTooltips.test.tsx +1066 -0
  169. package/Tests/App/Dashboard/RumOverviewPage.test.tsx +1195 -0
  170. package/Tests/App/Dashboard/ScheduledMaintenanceOverviewPage.test.tsx +2 -0
  171. package/Tests/App/Dashboard/ServerlessMetricTooltips.test.tsx +474 -0
  172. package/Tests/App/Dashboard/ServiceMapDatabaseLink.test.tsx +1085 -0
  173. package/Tests/App/Dashboard/ServiceMetricTooltips.test.tsx +772 -0
  174. package/Tests/App/Dashboard/SessionReplayAuditTable.test.tsx +56 -1
  175. package/Tests/App/Dashboard/TelemetryMetricsSignals.test.ts +1207 -0
  176. package/Tests/App/Dashboard/TelemetryResourceRetentionSettings.test.tsx +10 -0
  177. package/Tests/App/Dashboard/TelemetryResourceTabTooltips.test.tsx +437 -0
  178. package/Tests/App/Dashboard/TracesResourceFacets.test.tsx +2 -1
  179. package/Tests/App/Dashboard/VMwareMetricTooltips.test.ts +801 -0
  180. package/Tests/App/Dashboard/VMwareOverviewTooltips.test.tsx +601 -0
  181. package/Tests/App/Dashboard/VMwareResourcePagesTooltips.test.tsx +646 -0
  182. package/Tests/App/Dashboard/VMwareTooltipHarness.ts +145 -0
  183. package/Tests/App/StatusPage/StatusPageHeaderForeignHiddenRule.test.tsx +284 -0
  184. package/Tests/ClassStrings.ts +178 -0
  185. package/Tests/Fixtures/MobilePasskeyUser.json +1 -2
  186. package/Tests/ForeignHiddenRuleGuard.ts +2152 -0
  187. package/Tests/Models/DatabaseModels/DatabaseServerModels.test.ts +2250 -0
  188. package/Tests/Models/DatabaseModels/IncidentAlertModel.test.ts +554 -0
  189. package/Tests/Models/DatabaseModels/ResourceFeedModels.test.ts +24 -5
  190. package/Tests/Models/DatabaseModels/SessionReplayModels.test.ts +117 -0
  191. package/Tests/Models/DatabaseModels/StaticRuleCriteriaInheritance.test.ts +4 -2
  192. package/Tests/RenderedMarkup.ts +518 -0
  193. package/Tests/ResponsiveVisibility.test.ts +490 -4
  194. package/Tests/ResponsiveVisibility.ts +505 -52
  195. package/Tests/Server/Infrastructure/Postgres/AddConfigurableRuleCriteriaMigration.test.ts +3 -0
  196. package/Tests/Server/Infrastructure/Postgres/AddDatabaseServerTablesMigration.test.ts +541 -0
  197. package/Tests/Server/Infrastructure/Postgres/AddIncidentAlertMigration.test.ts +341 -0
  198. package/Tests/Server/Infrastructure/Postgres/AddSessionReplaySameOriginTracePropagationMigration.test.ts +247 -0
  199. package/Tests/Server/Infrastructure/Postgres/AddUserProjectSsoConsentMigration.test.ts +234 -0
  200. package/Tests/Server/Services/ContainerSnapshotUpsertPostgres.test.ts +319 -0
  201. package/Tests/Server/Services/CrossProjectRelationWriteGuard.test.ts +13 -0
  202. package/Tests/Server/Services/DatabaseServerEndpointService.test.ts +2033 -0
  203. package/Tests/Server/Services/DatabaseServerFeedAndOwnerServices.test.ts +529 -0
  204. package/Tests/Server/Services/DatabaseServerLifecycle.test.ts +3302 -0
  205. package/Tests/Server/Services/DatabaseServerRegistries.test.ts +603 -0
  206. package/Tests/Server/Services/DatabaseServerRuleEngines.test.ts +754 -0
  207. package/Tests/Server/Services/DatabaseServerService.test.ts +3558 -0
  208. package/Tests/Server/Services/DatabaseServerSqlPostgres.test.ts +2045 -0
  209. package/Tests/Server/Services/DatabaseServiceUpdateColumnsIfUnlockedPostgres.test.ts +362 -0
  210. package/Tests/Server/Services/DatabaseServiceUpdateColumnsIfUnlockedReply.test.ts +210 -0
  211. package/Tests/Server/Services/HookFreeWriteLengthClamp.test.ts +18 -0
  212. package/Tests/Server/Services/IncidentAlertPostgres.test.ts +903 -0
  213. package/Tests/Server/Services/IncidentAlertRegistration.test.ts +96 -0
  214. package/Tests/Server/Services/IncidentAlertService.test.ts +2225 -0
  215. package/Tests/Server/Services/IncidentAlertSloLinkSurvivesEdit.test.ts +2 -0
  216. package/Tests/Server/Services/IncidentAlertStateCascade.test.ts +970 -0
  217. package/Tests/Server/Services/IncidentCreateFromAlerts.test.ts +1284 -0
  218. package/Tests/Server/Services/IncomingCallPolicyEscalationRuleTarget.test.ts +225 -0
  219. package/Tests/Server/Services/InventoryItemDisplayName.test.ts +280 -2
  220. package/Tests/Server/Services/InventoryUpsertSchemaParity.test.ts +8 -2
  221. package/Tests/Server/Services/IoTDeviceLatestMetricsPostgres.test.ts +689 -0
  222. package/Tests/Server/Services/IoTDeviceService.test.ts +379 -0
  223. package/Tests/Server/Services/LatestMetricsValuesShape.test.ts +360 -0
  224. package/Tests/Server/Services/LlmModelPriceService.test.ts +402 -0
  225. package/Tests/Server/Services/OpenTelemetryResourceRetentionMemo.test.ts +7 -1
  226. package/Tests/Server/Services/OwnerRowUniqueness.test.ts +61 -9
  227. package/Tests/Server/Services/ReminderRuleLookupPostgres.test.ts +2250 -0
  228. package/Tests/Server/Services/ReminderRuleRefreshOpenSubjectsPaging.test.ts +653 -0
  229. package/Tests/Server/Services/ResourceUpdateLastSeenLivenessFallback.test.ts +68 -20
  230. package/Tests/Server/Services/StaticRuleCriteriaRuntimeCoverage.test.ts +3 -3
  231. package/Tests/Server/Services/TelemetryResourceFacetCounting.test.ts +9 -0
  232. package/Tests/Server/Services/UserProjectSsoConsentPostgres.test.ts +153 -0
  233. package/Tests/Server/Services/UserProjectSsoConsentService.test.ts +192 -0
  234. package/Tests/Server/Services/UserServiceFirstMasterAdminElection.test.ts +71 -0
  235. package/Tests/Server/Services/UserSignupIdTakeoverPostgres.test.ts +238 -0
  236. package/Tests/Server/Services/WorkspaceNotificationSummaryHelpers.test.ts +592 -0
  237. package/Tests/Server/Types/Billing/PayAsYouGoMeteredAuthorization.test.ts +3 -0
  238. package/Tests/Server/Types/Database/EventOverlayScopePostgres.test.ts +1 -0
  239. package/Tests/Server/Types/Database/FeedEventTypeFilterQuery.test.ts +11 -0
  240. package/Tests/Server/Types/Database/Permissions/InfrastructureOwnershipScope.test.ts +8 -0
  241. package/Tests/Server/Types/Database/QueryHelperBooleanForCriteriaBackedRule.test.ts +1094 -0
  242. package/Tests/Server/Utils/AI/ResourceTools.test.ts +134 -0
  243. package/Tests/Server/Utils/Monitor/Criteria/MetricMonitorCriteria.test.ts +41 -0
  244. package/Tests/Server/Utils/Monitor/Criteria/MetricMonitorCriteriaAnomalyUnits.test.ts +279 -9
  245. package/Tests/Server/Utils/Monitor/Criteria/MetricMonitorCriteriaDisplayContext.test.ts +933 -0
  246. package/Tests/Server/Utils/Monitor/DatabaseMaintenanceSuppression.test.ts +582 -0
  247. package/Tests/Server/Utils/Monitor/DatabaseServerMonitorLinking.test.ts +753 -0
  248. package/Tests/Server/Utils/Monitor/MonitorActionTimestamps.test.ts +1 -0
  249. package/Tests/Server/Utils/Monitor/MonitorAlertCriteriaReferences.test.ts +1 -0
  250. package/Tests/Server/Utils/Monitor/MonitorAlertResourceLinking.test.ts +119 -0
  251. package/Tests/Server/Utils/Monitor/MonitorCriteriaEvaluator.test.ts +60 -25
  252. package/Tests/Server/Utils/Monitor/MonitorCriteriaEvaluatorAffectedResourceEdgeCases.test.ts +1719 -0
  253. package/Tests/Server/Utils/Monitor/MonitorCriteriaEvaluatorKubernetesAffectedResources.test.ts +1447 -0
  254. package/Tests/Server/Utils/Monitor/MonitorCriteriaEvaluatorKubernetesRatioEmail.test.ts +352 -0
  255. package/Tests/Server/Utils/Monitor/MonitorCriteriaEvaluatorPlatformMetricUnits.test.ts +717 -0
  256. package/Tests/Server/Utils/Monitor/MonitorCriteriaEvaluatorPlatformRawScan.test.ts +2125 -0
  257. package/Tests/Server/Utils/Monitor/MonitorCriteriaEvaluatorPlatformSeriesAffectedResources.test.ts +1288 -0
  258. package/Tests/Server/Utils/Monitor/MonitorDependencySuppressionCreatorSkip.test.ts +1 -0
  259. package/Tests/Server/Utils/Monitor/MonitorIncidentCriteriaReferences.test.ts +1 -0
  260. package/Tests/Server/Utils/Monitor/MonitorIncidentMemberRoleMembership.test.ts +1 -0
  261. package/Tests/Server/Utils/Monitor/MonitorIncidentResourceLinking.test.ts +88 -0
  262. package/Tests/Server/Utils/Monitor/MonitorMaintenanceSuppression.test.ts +205 -0
  263. package/Tests/Server/Utils/Monitor/MonitorResourceContext.test.ts +62 -0
  264. package/Tests/Server/Utils/Monitor/MonitorResourceDatabaseMaintenance.test.ts +803 -0
  265. package/Tests/Server/Utils/Monitor/MonitorStepResourceIdentity.test.ts +133 -3
  266. package/Tests/Server/Utils/Monitor/MonitorSummaryPersistence.test.ts +1 -0
  267. package/Tests/Server/Utils/Monitor/PerSeriesRecoveryResolution.test.ts +472 -1
  268. package/Tests/Server/Utils/Monitor/PerSeriesSecondEntityAlerting.test.ts +1 -0
  269. package/Tests/Server/Utils/Monitor/SeriesResourceLinker.test.ts +236 -2
  270. package/Tests/Server/Utils/SeriesResourceLabels.test.ts +70 -0
  271. package/Tests/Server/Utils/SessionReplay/SessionReplayGateCachePolicy.test.ts +103 -0
  272. package/Tests/Server/Utils/StartServerProtobufContentType.test.ts +54 -0
  273. package/Tests/Server/Utils/Telemetry/DatabaseEndpointDiscovery.test.ts +1895 -0
  274. package/Tests/Server/Utils/Telemetry/EntityRegistry.test.ts +7 -0
  275. package/Tests/Server/Utils/Telemetry/LogExceptionExtractorSeverityGate.test.ts +90 -0
  276. package/Tests/Server/Utils/Telemetry/ResourceEntityFilter.test.ts +570 -0
  277. package/Tests/Server/Utils/Telemetry/ResourceFacetResolver.test.ts +97 -2
  278. package/Tests/Server/Utils/Telemetry/ServiceDependencyDiscovery.test.ts +1337 -0
  279. package/Tests/Server/Utils/Telemetry/TelemetryEntity.test.ts +295 -0
  280. package/Tests/Types/AI/AIResourceContext.test.ts +30 -0
  281. package/Tests/Types/DatabaseServer/DatabaseContainerClassifier.test.ts +3644 -0
  282. package/Tests/Types/DatabaseServer/DatabaseContainerCommand.test.ts +340 -0
  283. package/Tests/Types/DatabaseServer/DatabaseContainerCommandCorpus.ts +826 -0
  284. package/Tests/Types/DatabaseServer/DatabaseContainerCommandPostgres.test.ts +150 -0
  285. package/Tests/Types/DatabaseServer/DatabaseEndpoint.test.ts +2657 -0
  286. package/Tests/Types/DatabaseServer/DatabaseServerDiscoverySource.test.ts +64 -0
  287. package/Tests/Types/DatabaseServer/DatabaseServerEntityKeys.test.ts +952 -0
  288. package/Tests/Types/DatabaseServer/DatabaseServerMetricCatalog.test.ts +1161 -0
  289. package/Tests/Types/DatabaseServer/DatabaseSystem.test.ts +1514 -0
  290. package/Tests/Types/DatabaseServer/DatabaseTelemetryResolver.test.ts +1558 -0
  291. package/Tests/Types/Monitor/CephAlertTemplates.test.ts +255 -6
  292. package/Tests/Types/Monitor/DatabaseAlertTemplates.test.ts +2254 -0
  293. package/Tests/Types/Monitor/KubernetesAlertTemplates.test.ts +298 -0
  294. package/Tests/Types/Monitor/KubernetesMetricCatalog.test.ts +271 -0
  295. package/Tests/Types/Monitor/Recommendation/MonitorRecommendationCatalog.test.ts +253 -9
  296. package/Tests/Types/Monitor/Recommendation/MonitorRecommendationCoverage.test.ts +13 -5
  297. package/Tests/Types/Monitor/Recommendation/MonitorRecommendationNotificationMode.test.ts +4 -2
  298. package/Tests/Types/Monitor/Recommendation/MonitorRecommendationUtil.test.ts +111 -2
  299. package/Tests/Types/Monitor/Recommendation/RecommendationCriteriaBuilder.test.ts +61 -0
  300. package/Tests/Types/Monitor/SeriesContext/SeriesLabelDisplay.test.ts +114 -0
  301. package/Tests/Types/Monitor/Utils/KubernetesAgentEmittedMetrics.ts +181 -0
  302. package/Tests/Types/NetworkDevice/DiscoveredHostNamingStatus.test.ts +401 -0
  303. package/Tests/Types/Rum/WebVitals.test.ts +173 -0
  304. package/Tests/Types/Telemetry/ResourceEntityFacet.test.ts +4 -1
  305. package/Tests/Types/Telemetry/ResourceFacetCatalog.test.ts +24 -2
  306. package/Tests/UI/Components/Card.test.tsx +93 -2
  307. package/Tests/UI/Components/FeedOptions.test.ts +6 -0
  308. package/Tests/UI/Components/FeedOptionsButton.test.tsx +8 -1
  309. package/Tests/UI/Components/FieldLabelInfoCardTooltip.test.tsx +413 -0
  310. package/Tests/UI/Components/ForeignHiddenRuleResilience.test.tsx +1147 -0
  311. package/Tests/UI/Components/HeaderRightRail.test.tsx +41 -1
  312. package/Tests/UI/Components/InfoTooltip.test.tsx +242 -0
  313. package/Tests/UI/Components/LogsEntityNames.test.ts +16 -1
  314. package/Tests/UI/Components/LogsFacetSidebarHiddenFacets.test.tsx +7 -3
  315. package/Tests/UI/Components/ModelTable/BaseModelTableBulkDelete.test.tsx +207 -3
  316. package/Tests/UI/Components/ModelTable/BaseModelTableBulkDeleteVerb.test.tsx +367 -0
  317. package/Tests/UI/Components/ModelTable/BaseModelTableCreateButtonTitle.test.tsx +275 -0
  318. package/Tests/UI/Components/ResourceFacetConfigs.test.ts +2 -1
  319. package/Tests/UI/Components/RuleCriteria/RuleCriteriaModelTable.test.tsx +3 -3
  320. package/Tests/UI/Components/SrOnlyForeignRule.test.tsx +994 -0
  321. package/Tests/UI/Components/StatusPage/ResourceListSelection.test.tsx +34 -1
  322. package/Tests/UI/Components/TableHeaderTooltip.test.tsx +662 -0
  323. package/Tests/UI/Components/TelemetryFacetSidebarHiddenFacets.test.tsx +4 -1
  324. package/Tests/UI/ForeignHiddenRuleGuard.test.ts +1951 -0
  325. package/Tests/UI/Rum/PrivacySummaryCard.test.tsx +166 -9
  326. package/Tests/UI/Rum/RecordingHealthTooltips.test.tsx +447 -0
  327. package/Tests/UI/Rum/ReplayCorrelationPanel.test.tsx +164 -0
  328. package/Tests/UI/Rum/ReplayFrameCapture.test.ts +6750 -0
  329. package/Tests/UI/Rum/ReplayPlayerChrome.test.tsx +19 -1
  330. package/Tests/UI/Rum/ReplayRail.test.tsx +723 -12
  331. package/Tests/UI/Rum/ReplayRailDetail.test.tsx +86 -0
  332. package/Tests/UI/Rum/ReplayScreenshot.test.ts +2124 -0
  333. package/Tests/UI/Rum/ReplayScreenshotActions.test.tsx +3288 -0
  334. package/Tests/UI/Rum/ReplayStage.test.tsx +62 -0
  335. package/Tests/UI/Rum/ReplayStageOverlays.test.tsx +983 -2
  336. package/Tests/UI/Rum/ReplayTabSwitcher.test.tsx +19 -1
  337. package/Tests/UI/Rum/SessionReplaySettingsPolicyLoading.test.tsx +149 -0
  338. package/Tests/UI/Rum/SessionReplaySetupGuide.test.tsx +107 -6
  339. package/Tests/UI/Rum/SessionReplayUsersTableTooltips.test.tsx +330 -0
  340. package/Tests/UI/Rum/UserFlowTooltips.test.tsx +886 -0
  341. package/Tests/UI/TailwindPlayCdnForeignHiddenRule.test.ts +1005 -0
  342. package/Tests/UI/ThemeGroupHoverReveal.test.ts +847 -0
  343. package/Tests/UI/Utils/Breadcrumb/fixtures/RealBreadcrumbTrails.ts +80 -0
  344. package/Tests/UI/Utils/Breadcrumb/fixtures/RealRoutePatterns.ts +23 -0
  345. package/Tests/UI/Utils/ModelAPISsoRedirect.test.ts +127 -0
  346. package/Tests/UI/Utils/Navigation.test.ts +102 -0
  347. package/Tests/UI/Utils/PermissionGate.test.ts +76 -0
  348. package/Tests/UI/Utils/Telemetry/TelemetryEntityNames.test.ts +23 -0
  349. package/Tests/Utils/Incident/IncidentFromAlerts.test.ts +696 -0
  350. package/Tests/Utils/LabelRuleImportExport.test.ts +5 -0
  351. package/Tests/Utils/MetricUnitUtil.test.ts +227 -2
  352. package/Tests/Utils/Monitor/MetricValueFormatter.test.ts +288 -2
  353. package/Tests/Utils/Monitor/PlatformResourceIdentityAndUnits.test.ts +1559 -0
  354. package/Tests/Utils/NetworkDiscovery/DiscoveredHostNamingDiagnosis.test.ts +2546 -0
  355. package/Tests/Utils/NetworkDiscovery/DiscoveredHostUtil.test.ts +315 -0
  356. package/Tests/Utils/NetworkDiscovery/DiscoveryReverseDnsChain.test.ts +336 -1
  357. package/Tests/Utils/NetworkDiscovery/NetbiosNameUtil.test.ts +244 -0
  358. package/Tests/Utils/Rum/SessionTraceState.test.ts +239 -0
  359. package/Tests/Utils/ValueFormatter.test.ts +50 -0
  360. package/Tests/tsconfig.json +16 -0
  361. package/Types/AI/AIResourceContext.ts +7 -0
  362. package/Types/Dashboard/DashboardTemplates.ts +2 -1
  363. package/Types/DatabaseServer/DatabaseConnectionSpan.ts +77 -0
  364. package/Types/DatabaseServer/DatabaseContainerClassifier.ts +2068 -0
  365. package/Types/DatabaseServer/DatabaseContainerCommand.ts +801 -0
  366. package/Types/DatabaseServer/DatabaseEndpoint.ts +1943 -0
  367. package/Types/DatabaseServer/DatabaseServerDiscoverySource.ts +68 -0
  368. package/Types/DatabaseServer/DatabaseServerMetricCatalog.ts +966 -0
  369. package/Types/DatabaseServer/DatabaseSystem.ts +2124 -0
  370. package/Types/DatabaseServer/DatabaseTelemetryResolver.ts +555 -0
  371. package/Types/Email/EmailTemplateType.ts +1 -0
  372. package/Types/Incident/IncidentAlertLink.ts +38 -0
  373. package/Types/Monitor/CephAlertTemplates.ts +18 -0
  374. package/Types/Monitor/DatabaseAlertTemplates.ts +2020 -0
  375. package/Types/Monitor/KubernetesAlertTemplates.ts +64 -24
  376. package/Types/Monitor/KubernetesMetricCatalog.ts +118 -19
  377. package/Types/Monitor/MetricMonitor/MetricCriteriaContext.ts +14 -0
  378. package/Types/Monitor/MetricMonitor/MetricMonitorResponse.ts +93 -10
  379. package/Types/Monitor/Recommendation/MonitorRecommendationCatalog.ts +109 -8
  380. package/Types/Monitor/Recommendation/MonitorRecommendationTypes.ts +36 -7
  381. package/Types/Monitor/Recommendation/MonitorRecommendationUtil.ts +43 -2
  382. package/Types/Monitor/Recommendation/RecommendationCriteriaBuilder.ts +41 -6
  383. package/Types/Monitor/SeriesContext/SeriesLabelDisplay.ts +26 -0
  384. package/Types/NetworkDevice/DiscoveredHostNamingStatus.ts +147 -0
  385. package/Types/Permission.ts +315 -0
  386. package/Types/Probe/ProbeApiIngestResponse.ts +8 -0
  387. package/Types/Rules/RuleCriteriaFieldRegistry.ts +10 -0
  388. package/Types/Rules/RuleRun.ts +12 -0
  389. package/Types/Rum/SessionReplay.ts +25 -6
  390. package/Types/Rum/WebVitals.ts +52 -0
  391. package/Types/Telemetry/EntityType.ts +23 -0
  392. package/Types/Telemetry/ResourceFacetCatalog.ts +14 -0
  393. package/Types/Telemetry/ServiceType.ts +8 -0
  394. package/UI/Components/Banner/Banner.tsx +1 -1
  395. package/UI/Components/Card/Card.tsx +1 -1
  396. package/UI/Components/Charts/ChartGroup/ChartGroup.tsx +2 -2
  397. package/UI/Components/Charts/Line/LineChart.tsx +7 -0
  398. package/UI/Components/CommandPalette/CommandPalette.tsx +1 -1
  399. package/UI/Components/Date/StartAndEndDate.tsx +5 -5
  400. package/UI/Components/Detail/FieldLabel.tsx +8 -0
  401. package/UI/Components/Diagram/HorizontalStepChain.tsx +1 -1
  402. package/UI/Components/Feed/FeedOptionsButton.tsx +1 -1
  403. package/UI/Components/Forms/BasicForm.tsx +1 -1
  404. package/UI/Components/Header/Header.tsx +1 -1
  405. package/UI/Components/Header/HeaderIconDropdownButton.tsx +1 -1
  406. package/UI/Components/HeaderAlert/HeaderAlert.tsx +1 -1
  407. package/UI/Components/InfoCard/InfoCard.tsx +47 -1
  408. package/UI/Components/LogsViewer/components/FacetValueRow.tsx +1 -1
  409. package/UI/Components/LogsViewer/components/LogsFacetSidebar.tsx +1 -1
  410. package/UI/Components/Modal/ModalFooter.tsx +1 -1
  411. package/UI/Components/ModelDetail/CardModelDetail.tsx +2 -2
  412. package/UI/Components/ModelTable/BaseModelTable.tsx +99 -21
  413. package/UI/Components/ModelTable/Column.ts +5 -0
  414. package/UI/Components/Navbar/NavBar.tsx +9 -2
  415. package/UI/Components/Navbar/NavBarMenuModal.tsx +2 -2
  416. package/UI/Components/Page/Page.tsx +1 -1
  417. package/UI/Components/Pagination/Pagination.tsx +3 -3
  418. package/UI/Components/ProgressButtons/ProgressButtonItem.tsx +1 -1
  419. package/UI/Components/SideMenu/SideMenu.tsx +4 -1
  420. package/UI/Components/StatusPage/ResourceGroupNavigator.tsx +4 -2
  421. package/UI/Components/StatusPage/ResourceList.tsx +6 -6
  422. package/UI/Components/Table/TableHeader.tsx +47 -2
  423. package/UI/Components/Table/Types/Column.ts +7 -0
  424. package/UI/Components/TelemetryViewer/components/TelemetryFacetSidebar.tsx +1 -1
  425. package/UI/Components/TelemetryViewer/components/TelemetryFacetValueRow.tsx +1 -1
  426. package/UI/Components/Tooltip/InfoTooltip.tsx +78 -0
  427. package/UI/Components/Workflow/ColumnEditor/ModelQueryBuilder.tsx +1 -1
  428. package/UI/Components/Workflow/ComponentsModal.tsx +2 -2
  429. package/UI/Components/Workflow/StepTraceViewer.tsx +1 -1
  430. package/UI/Styles/Theme.css +8 -1
  431. package/UI/Utils/Navigation.ts +89 -42
  432. package/UI/Utils/PermissionGate.ts +11 -2
  433. package/UI/Utils/Telemetry/TelemetryEntityNames.ts +7 -0
  434. package/UI/Utils/TelemetryService.ts +4 -3
  435. package/Utils/Incident/IncidentFromAlerts.ts +516 -0
  436. package/Utils/LabelRuleImportExport.ts +2 -0
  437. package/Utils/MetricUnitUtil.ts +103 -11
  438. package/Utils/Monitor/MetricValueFormatter.ts +66 -13
  439. package/Utils/Monitor/PlatformMetricUnitUtil.ts +215 -0
  440. package/Utils/Monitor/PlatformResourceIdentity.ts +514 -0
  441. package/Utils/NetworkDiscovery/DiscoveredHostNamingDiagnosis.ts +425 -0
  442. package/Utils/NetworkDiscovery/DiscoveredHostUtil.ts +32 -0
  443. package/Utils/NetworkDiscovery/NetbiosNameUtil.ts +73 -0
  444. package/Utils/Rum/SessionTraceState.ts +212 -0
  445. package/Utils/Telemetry/DatabaseServerEntityKeys.ts +275 -0
  446. package/Utils/Telemetry/EntityKey.ts +176 -0
  447. package/Utils/ValueFormatter.ts +16 -0
  448. package/build/dist/Models/DatabaseModels/Alert.js +54 -0
  449. package/build/dist/Models/DatabaseModels/Alert.js.map +1 -1
  450. package/build/dist/Models/DatabaseModels/AlertFeed.js +2 -0
  451. package/build/dist/Models/DatabaseModels/AlertFeed.js.map +1 -1
  452. package/build/dist/Models/DatabaseModels/DatabaseServer.js +1683 -0
  453. package/build/dist/Models/DatabaseModels/DatabaseServer.js.map +1 -0
  454. package/build/dist/Models/DatabaseModels/DatabaseServerEndpoint.js +559 -0
  455. package/build/dist/Models/DatabaseModels/DatabaseServerEndpoint.js.map +1 -0
  456. package/build/dist/Models/DatabaseModels/DatabaseServerFeed.js +648 -0
  457. package/build/dist/Models/DatabaseModels/DatabaseServerFeed.js.map +1 -0
  458. package/build/dist/Models/DatabaseModels/DatabaseServerLabelRule.js +522 -0
  459. package/build/dist/Models/DatabaseModels/DatabaseServerLabelRule.js.map +1 -0
  460. package/build/dist/Models/DatabaseModels/DatabaseServerOwnerRule.js +603 -0
  461. package/build/dist/Models/DatabaseModels/DatabaseServerOwnerRule.js.map +1 -0
  462. package/build/dist/Models/DatabaseModels/DatabaseServerOwnerTeam.js +506 -0
  463. package/build/dist/Models/DatabaseModels/DatabaseServerOwnerTeam.js.map +1 -0
  464. package/build/dist/Models/DatabaseModels/DatabaseServerOwnerUser.js +505 -0
  465. package/build/dist/Models/DatabaseModels/DatabaseServerOwnerUser.js.map +1 -0
  466. package/build/dist/Models/DatabaseModels/Incident.js +54 -0
  467. package/build/dist/Models/DatabaseModels/Incident.js.map +1 -1
  468. package/build/dist/Models/DatabaseModels/IncidentAlert.js +553 -0
  469. package/build/dist/Models/DatabaseModels/IncidentAlert.js.map +1 -0
  470. package/build/dist/Models/DatabaseModels/IncidentFeed.js +2 -0
  471. package/build/dist/Models/DatabaseModels/IncidentFeed.js.map +1 -1
  472. package/build/dist/Models/DatabaseModels/Index.js +18 -0
  473. package/build/dist/Models/DatabaseModels/Index.js.map +1 -1
  474. package/build/dist/Models/DatabaseModels/NetworkDeviceDiscoveryScan.js.map +1 -1
  475. package/build/dist/Models/DatabaseModels/Project.js +62 -0
  476. package/build/dist/Models/DatabaseModels/Project.js.map +1 -1
  477. package/build/dist/Models/DatabaseModels/RumApplication.js +53 -1
  478. package/build/dist/Models/DatabaseModels/RumApplication.js.map +1 -1
  479. package/build/dist/Models/DatabaseModels/ScheduledMaintenance.js +54 -0
  480. package/build/dist/Models/DatabaseModels/ScheduledMaintenance.js.map +1 -1
  481. package/build/dist/Models/DatabaseModels/TelemetryException.js +2 -0
  482. package/build/dist/Models/DatabaseModels/TelemetryException.js.map +1 -1
  483. package/build/dist/Models/DatabaseModels/UserProjectSsoConsent.js +162 -0
  484. package/build/dist/Models/DatabaseModels/UserProjectSsoConsent.js.map +1 -0
  485. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1794800000000-AddSessionReplaySameOriginTracePropagation.js +20 -0
  486. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1794800000000-AddSessionReplaySameOriginTracePropagation.js.map +1 -0
  487. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1794900000000-AddIncidentAlert.js +42 -0
  488. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1794900000000-AddIncidentAlert.js.map +1 -0
  489. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1795000000000-AddDatabaseServerTables.js +240 -0
  490. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1795000000000-AddDatabaseServerTables.js.map +1 -0
  491. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1795100000000-AddUserProjectSsoConsent.js +26 -0
  492. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1795100000000-AddUserProjectSsoConsent.js.map +1 -0
  493. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +8 -0
  494. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
  495. package/build/dist/Server/Middleware/MultipartFormData.js +1 -1
  496. package/build/dist/Server/Middleware/TelemetryIngest.js +15 -8
  497. package/build/dist/Server/Middleware/TelemetryIngest.js.map +1 -1
  498. package/build/dist/Server/Services/AlertReminderRuleService.js +72 -23
  499. package/build/dist/Server/Services/AlertReminderRuleService.js.map +1 -1
  500. package/build/dist/Server/Services/DatabaseServerEndpointService.js +694 -0
  501. package/build/dist/Server/Services/DatabaseServerEndpointService.js.map +1 -0
  502. package/build/dist/Server/Services/DatabaseServerFeedService.js +110 -0
  503. package/build/dist/Server/Services/DatabaseServerFeedService.js.map +1 -0
  504. package/build/dist/Server/Services/DatabaseServerLabelRuleEngineService.js +272 -0
  505. package/build/dist/Server/Services/DatabaseServerLabelRuleEngineService.js.map +1 -0
  506. package/build/dist/Server/Services/DatabaseServerLabelRuleService.js +13 -0
  507. package/build/dist/Server/Services/DatabaseServerLabelRuleService.js.map +1 -0
  508. package/build/dist/Server/Services/DatabaseServerOwnerRuleEngineService.js +340 -0
  509. package/build/dist/Server/Services/DatabaseServerOwnerRuleEngineService.js.map +1 -0
  510. package/build/dist/Server/Services/DatabaseServerOwnerRuleService.js +13 -0
  511. package/build/dist/Server/Services/DatabaseServerOwnerRuleService.js.map +1 -0
  512. package/build/dist/Server/Services/DatabaseServerOwnerTeamService.js +160 -0
  513. package/build/dist/Server/Services/DatabaseServerOwnerTeamService.js.map +1 -0
  514. package/build/dist/Server/Services/DatabaseServerOwnerUserService.js +153 -0
  515. package/build/dist/Server/Services/DatabaseServerOwnerUserService.js.map +1 -0
  516. package/build/dist/Server/Services/DatabaseServerService.js +3272 -0
  517. package/build/dist/Server/Services/DatabaseServerService.js.map +1 -0
  518. package/build/dist/Server/Services/DatabaseService.js +8 -4
  519. package/build/dist/Server/Services/DatabaseService.js.map +1 -1
  520. package/build/dist/Server/Services/DockerResourceService.js +30 -3
  521. package/build/dist/Server/Services/DockerResourceService.js.map +1 -1
  522. package/build/dist/Server/Services/IncidentAlertService.js +1370 -0
  523. package/build/dist/Server/Services/IncidentAlertService.js.map +1 -0
  524. package/build/dist/Server/Services/IncidentReminderRuleService.js +73 -23
  525. package/build/dist/Server/Services/IncidentReminderRuleService.js.map +1 -1
  526. package/build/dist/Server/Services/IncidentService.js +164 -12
  527. package/build/dist/Server/Services/IncidentService.js.map +1 -1
  528. package/build/dist/Server/Services/IncidentStateTimelineService.js +21 -0
  529. package/build/dist/Server/Services/IncidentStateTimelineService.js.map +1 -1
  530. package/build/dist/Server/Services/Index.js +18 -0
  531. package/build/dist/Server/Services/Index.js.map +1 -1
  532. package/build/dist/Server/Services/InventoryItemService.js +88 -5
  533. package/build/dist/Server/Services/InventoryItemService.js.map +1 -1
  534. package/build/dist/Server/Services/IoTDeviceService.js +111 -24
  535. package/build/dist/Server/Services/IoTDeviceService.js.map +1 -1
  536. package/build/dist/Server/Services/OpenTelemetryIngestService.js +24 -9
  537. package/build/dist/Server/Services/OpenTelemetryIngestService.js.map +1 -1
  538. package/build/dist/Server/Services/PodmanResourceService.js +30 -3
  539. package/build/dist/Server/Services/PodmanResourceService.js.map +1 -1
  540. package/build/dist/Server/Services/ScheduledMaintenanceReminderRuleService.js +75 -23
  541. package/build/dist/Server/Services/ScheduledMaintenanceReminderRuleService.js.map +1 -1
  542. package/build/dist/Server/Services/ServiceService.js +1 -1
  543. package/build/dist/Server/Services/ServiceService.js.map +1 -1
  544. package/build/dist/Server/Services/TelemetryUsageBillingService.js +23 -2
  545. package/build/dist/Server/Services/TelemetryUsageBillingService.js.map +1 -1
  546. package/build/dist/Server/Services/UserProjectSsoConsentService.js +79 -0
  547. package/build/dist/Server/Services/UserProjectSsoConsentService.js.map +1 -0
  548. package/build/dist/Server/Services/UserService.js +13 -1
  549. package/build/dist/Server/Services/UserService.js.map +1 -1
  550. package/build/dist/Server/Types/Database/Permissions/OwnerTableRegistry.js +18 -0
  551. package/build/dist/Server/Types/Database/Permissions/OwnerTableRegistry.js.map +1 -1
  552. package/build/dist/Server/Types/Database/QueryHelper.js +26 -1
  553. package/build/dist/Server/Types/Database/QueryHelper.js.map +1 -1
  554. package/build/dist/Server/Utils/AI/Toolbox/ResourceTools.js +46 -0
  555. package/build/dist/Server/Utils/AI/Toolbox/ResourceTools.js.map +1 -1
  556. package/build/dist/Server/Utils/Database/AffectedResourceRelations.js +6 -0
  557. package/build/dist/Server/Utils/Database/AffectedResourceRelations.js.map +1 -1
  558. package/build/dist/Server/Utils/Monitor/Criteria/MetricMonitorCriteria.js +134 -13
  559. package/build/dist/Server/Utils/Monitor/Criteria/MetricMonitorCriteria.js.map +1 -1
  560. package/build/dist/Server/Utils/Monitor/MonitorAlert.js +22 -6
  561. package/build/dist/Server/Utils/Monitor/MonitorAlert.js.map +1 -1
  562. package/build/dist/Server/Utils/Monitor/MonitorCriteriaEvaluator.js +1489 -524
  563. package/build/dist/Server/Utils/Monitor/MonitorCriteriaEvaluator.js.map +1 -1
  564. package/build/dist/Server/Utils/Monitor/MonitorIncident.js +22 -6
  565. package/build/dist/Server/Utils/Monitor/MonitorIncident.js.map +1 -1
  566. package/build/dist/Server/Utils/Monitor/MonitorMaintenanceSuppression.js +196 -6
  567. package/build/dist/Server/Utils/Monitor/MonitorMaintenanceSuppression.js.map +1 -1
  568. package/build/dist/Server/Utils/Monitor/MonitorResource.js +36 -9
  569. package/build/dist/Server/Utils/Monitor/MonitorResource.js.map +1 -1
  570. package/build/dist/Server/Utils/Monitor/MonitorResourceContext.js +1 -0
  571. package/build/dist/Server/Utils/Monitor/MonitorResourceContext.js.map +1 -1
  572. package/build/dist/Server/Utils/Monitor/MonitorStepResourceIdentity.js +175 -17
  573. package/build/dist/Server/Utils/Monitor/MonitorStepResourceIdentity.js.map +1 -1
  574. package/build/dist/Server/Utils/Monitor/PerSeriesResolutionRootCause.js +29 -0
  575. package/build/dist/Server/Utils/Monitor/PerSeriesResolutionRootCause.js.map +1 -0
  576. package/build/dist/Server/Utils/Monitor/SeriesResourceLabels.js +211 -0
  577. package/build/dist/Server/Utils/Monitor/SeriesResourceLabels.js.map +1 -1
  578. package/build/dist/Server/Utils/Monitor/SeriesResourceLinker.js +82 -10
  579. package/build/dist/Server/Utils/Monitor/SeriesResourceLinker.js.map +1 -1
  580. package/build/dist/Server/Utils/Rules/RuleRun/RuleRunRegistry.js +25 -0
  581. package/build/dist/Server/Utils/Rules/RuleRun/RuleRunRegistry.js.map +1 -1
  582. package/build/dist/Server/Utils/SessionReplay/SessionReplayGateCache.js +8 -0
  583. package/build/dist/Server/Utils/SessionReplay/SessionReplayGateCache.js.map +1 -1
  584. package/build/dist/Server/Utils/StartServer.js +20 -4
  585. package/build/dist/Server/Utils/StartServer.js.map +1 -1
  586. package/build/dist/Server/Utils/TeamMember/ProjectLeaveResourceCleanup.js +2 -0
  587. package/build/dist/Server/Utils/TeamMember/ProjectLeaveResourceCleanup.js.map +1 -1
  588. package/build/dist/Server/Utils/Telemetry/DatabaseEndpointDiscovery.js +442 -0
  589. package/build/dist/Server/Utils/Telemetry/DatabaseEndpointDiscovery.js.map +1 -0
  590. package/build/dist/Server/Utils/Telemetry/EntityRegistry.js +5 -1
  591. package/build/dist/Server/Utils/Telemetry/EntityRegistry.js.map +1 -1
  592. package/build/dist/Server/Utils/Telemetry/LogExceptionExtractor.js +15 -1
  593. package/build/dist/Server/Utils/Telemetry/LogExceptionExtractor.js.map +1 -1
  594. package/build/dist/Server/Utils/Telemetry/ResourceEntityFilter.js +121 -5
  595. package/build/dist/Server/Utils/Telemetry/ResourceEntityFilter.js.map +1 -1
  596. package/build/dist/Server/Utils/Telemetry/ResourceFacetResolver.js +12 -0
  597. package/build/dist/Server/Utils/Telemetry/ResourceFacetResolver.js.map +1 -1
  598. package/build/dist/Server/Utils/Telemetry/ServiceDependencyDiscovery.js +438 -36
  599. package/build/dist/Server/Utils/Telemetry/ServiceDependencyDiscovery.js.map +1 -1
  600. package/build/dist/Server/Utils/Telemetry/Telemetry.js +12 -0
  601. package/build/dist/Server/Utils/Telemetry/Telemetry.js.map +1 -1
  602. package/build/dist/Server/Utils/Telemetry/TelemetryEntity.js +17 -18
  603. package/build/dist/Server/Utils/Telemetry/TelemetryEntity.js.map +1 -1
  604. package/build/dist/Server/Utils/Telemetry/TelemetryIngestionKeyGuard.js +16 -10
  605. package/build/dist/Server/Utils/Telemetry/TelemetryIngestionKeyGuard.js.map +1 -1
  606. package/build/dist/Types/AI/AIResourceContext.js +7 -0
  607. package/build/dist/Types/AI/AIResourceContext.js.map +1 -1
  608. package/build/dist/Types/Dashboard/DashboardTemplates.js +2 -1
  609. package/build/dist/Types/Dashboard/DashboardTemplates.js.map +1 -1
  610. package/build/dist/Types/DatabaseServer/DatabaseConnectionSpan.js +71 -0
  611. package/build/dist/Types/DatabaseServer/DatabaseConnectionSpan.js.map +1 -0
  612. package/build/dist/Types/DatabaseServer/DatabaseContainerClassifier.js +1462 -0
  613. package/build/dist/Types/DatabaseServer/DatabaseContainerClassifier.js.map +1 -0
  614. package/build/dist/Types/DatabaseServer/DatabaseContainerCommand.js +691 -0
  615. package/build/dist/Types/DatabaseServer/DatabaseContainerCommand.js.map +1 -0
  616. package/build/dist/Types/DatabaseServer/DatabaseEndpoint.js +1407 -0
  617. package/build/dist/Types/DatabaseServer/DatabaseEndpoint.js.map +1 -0
  618. package/build/dist/Types/DatabaseServer/DatabaseServerDiscoverySource.js +60 -0
  619. package/build/dist/Types/DatabaseServer/DatabaseServerDiscoverySource.js.map +1 -0
  620. package/build/dist/Types/DatabaseServer/DatabaseServerMetricCatalog.js +804 -0
  621. package/build/dist/Types/DatabaseServer/DatabaseServerMetricCatalog.js.map +1 -0
  622. package/build/dist/Types/DatabaseServer/DatabaseSystem.js +1860 -0
  623. package/build/dist/Types/DatabaseServer/DatabaseSystem.js.map +1 -0
  624. package/build/dist/Types/DatabaseServer/DatabaseTelemetryResolver.js +406 -0
  625. package/build/dist/Types/DatabaseServer/DatabaseTelemetryResolver.js.map +1 -0
  626. package/build/dist/Types/Email/EmailTemplateType.js +1 -0
  627. package/build/dist/Types/Email/EmailTemplateType.js.map +1 -1
  628. package/build/dist/Types/Incident/IncidentAlertLink.js +34 -0
  629. package/build/dist/Types/Incident/IncidentAlertLink.js.map +1 -0
  630. package/build/dist/Types/Monitor/CephAlertTemplates.js +18 -0
  631. package/build/dist/Types/Monitor/CephAlertTemplates.js.map +1 -1
  632. package/build/dist/Types/Monitor/DatabaseAlertTemplates.js +1518 -0
  633. package/build/dist/Types/Monitor/DatabaseAlertTemplates.js.map +1 -0
  634. package/build/dist/Types/Monitor/KubernetesAlertTemplates.js +57 -24
  635. package/build/dist/Types/Monitor/KubernetesAlertTemplates.js.map +1 -1
  636. package/build/dist/Types/Monitor/KubernetesMetricCatalog.js +104 -18
  637. package/build/dist/Types/Monitor/KubernetesMetricCatalog.js.map +1 -1
  638. package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationCatalog.js +80 -3
  639. package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationCatalog.js.map +1 -1
  640. package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationTypes.js +10 -3
  641. package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationTypes.js.map +1 -1
  642. package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationUtil.js +29 -0
  643. package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationUtil.js.map +1 -1
  644. package/build/dist/Types/Monitor/Recommendation/RecommendationCriteriaBuilder.js +21 -6
  645. package/build/dist/Types/Monitor/Recommendation/RecommendationCriteriaBuilder.js.map +1 -1
  646. package/build/dist/Types/Monitor/SeriesContext/SeriesLabelDisplay.js +25 -0
  647. package/build/dist/Types/Monitor/SeriesContext/SeriesLabelDisplay.js.map +1 -1
  648. package/build/dist/Types/NetworkDevice/DiscoveredHostNamingStatus.js +136 -0
  649. package/build/dist/Types/NetworkDevice/DiscoveredHostNamingStatus.js.map +1 -0
  650. package/build/dist/Types/Permission.js +276 -0
  651. package/build/dist/Types/Permission.js.map +1 -1
  652. package/build/dist/Types/Rules/RuleCriteriaFieldRegistry.js +10 -0
  653. package/build/dist/Types/Rules/RuleCriteriaFieldRegistry.js.map +1 -1
  654. package/build/dist/Types/Rules/RuleRun.js +4 -0
  655. package/build/dist/Types/Rules/RuleRun.js.map +1 -1
  656. package/build/dist/Types/Rum/WebVitals.js +25 -0
  657. package/build/dist/Types/Rum/WebVitals.js.map +1 -1
  658. package/build/dist/Types/Telemetry/EntityType.js +23 -0
  659. package/build/dist/Types/Telemetry/EntityType.js.map +1 -1
  660. package/build/dist/Types/Telemetry/ResourceFacetCatalog.js +14 -0
  661. package/build/dist/Types/Telemetry/ResourceFacetCatalog.js.map +1 -1
  662. package/build/dist/Types/Telemetry/ServiceType.js +8 -0
  663. package/build/dist/Types/Telemetry/ServiceType.js.map +1 -1
  664. package/build/dist/UI/Components/Banner/Banner.js +1 -1
  665. package/build/dist/UI/Components/Banner/Banner.js.map +1 -1
  666. package/build/dist/UI/Components/Card/Card.js +1 -1
  667. package/build/dist/UI/Components/Card/Card.js.map +1 -1
  668. package/build/dist/UI/Components/Charts/ChartGroup/ChartGroup.js +2 -2
  669. package/build/dist/UI/Components/Charts/ChartGroup/ChartGroup.js.map +1 -1
  670. package/build/dist/UI/Components/Charts/Line/LineChart.js +1 -1
  671. package/build/dist/UI/Components/Charts/Line/LineChart.js.map +1 -1
  672. package/build/dist/UI/Components/CommandPalette/CommandPalette.js +1 -1
  673. package/build/dist/UI/Components/CommandPalette/CommandPalette.js.map +1 -1
  674. package/build/dist/UI/Components/Date/StartAndEndDate.js +5 -5
  675. package/build/dist/UI/Components/Date/StartAndEndDate.js.map +1 -1
  676. package/build/dist/UI/Components/Detail/FieldLabel.js +2 -0
  677. package/build/dist/UI/Components/Detail/FieldLabel.js.map +1 -1
  678. package/build/dist/UI/Components/Diagram/HorizontalStepChain.js +1 -1
  679. package/build/dist/UI/Components/Diagram/HorizontalStepChain.js.map +1 -1
  680. package/build/dist/UI/Components/Feed/FeedOptionsButton.js +1 -1
  681. package/build/dist/UI/Components/Feed/FeedOptionsButton.js.map +1 -1
  682. package/build/dist/UI/Components/Forms/BasicForm.js +1 -1
  683. package/build/dist/UI/Components/Forms/BasicForm.js.map +1 -1
  684. package/build/dist/UI/Components/Header/HeaderIconDropdownButton.js +1 -1
  685. package/build/dist/UI/Components/Header/HeaderIconDropdownButton.js.map +1 -1
  686. package/build/dist/UI/Components/HeaderAlert/HeaderAlert.js +1 -1
  687. package/build/dist/UI/Components/HeaderAlert/HeaderAlert.js.map +1 -1
  688. package/build/dist/UI/Components/InfoCard/InfoCard.js +22 -1
  689. package/build/dist/UI/Components/InfoCard/InfoCard.js.map +1 -1
  690. package/build/dist/UI/Components/LogsViewer/components/FacetValueRow.js +1 -1
  691. package/build/dist/UI/Components/LogsViewer/components/FacetValueRow.js.map +1 -1
  692. package/build/dist/UI/Components/LogsViewer/components/LogsFacetSidebar.js +1 -1
  693. package/build/dist/UI/Components/LogsViewer/components/LogsFacetSidebar.js.map +1 -1
  694. package/build/dist/UI/Components/Modal/ModalFooter.js +1 -1
  695. package/build/dist/UI/Components/Modal/ModalFooter.js.map +1 -1
  696. package/build/dist/UI/Components/ModelDetail/CardModelDetail.js +2 -2
  697. package/build/dist/UI/Components/ModelDetail/CardModelDetail.js.map +1 -1
  698. package/build/dist/UI/Components/ModelTable/BaseModelTable.js +70 -18
  699. package/build/dist/UI/Components/ModelTable/BaseModelTable.js.map +1 -1
  700. package/build/dist/UI/Components/Navbar/NavBar.js +9 -2
  701. package/build/dist/UI/Components/Navbar/NavBar.js.map +1 -1
  702. package/build/dist/UI/Components/Navbar/NavBarMenuModal.js +2 -2
  703. package/build/dist/UI/Components/Navbar/NavBarMenuModal.js.map +1 -1
  704. package/build/dist/UI/Components/Page/Page.js +1 -1
  705. package/build/dist/UI/Components/Page/Page.js.map +1 -1
  706. package/build/dist/UI/Components/Pagination/Pagination.js +3 -3
  707. package/build/dist/UI/Components/Pagination/Pagination.js.map +1 -1
  708. package/build/dist/UI/Components/ProgressButtons/ProgressButtonItem.js +1 -1
  709. package/build/dist/UI/Components/ProgressButtons/ProgressButtonItem.js.map +1 -1
  710. package/build/dist/UI/Components/SideMenu/SideMenu.js +4 -1
  711. package/build/dist/UI/Components/SideMenu/SideMenu.js.map +1 -1
  712. package/build/dist/UI/Components/StatusPage/ResourceGroupNavigator.js +3 -1
  713. package/build/dist/UI/Components/StatusPage/ResourceGroupNavigator.js.map +1 -1
  714. package/build/dist/UI/Components/StatusPage/ResourceList.js +6 -6
  715. package/build/dist/UI/Components/StatusPage/ResourceList.js.map +1 -1
  716. package/build/dist/UI/Components/Table/TableHeader.js +18 -2
  717. package/build/dist/UI/Components/Table/TableHeader.js.map +1 -1
  718. package/build/dist/UI/Components/TelemetryViewer/components/TelemetryFacetSidebar.js +1 -1
  719. package/build/dist/UI/Components/TelemetryViewer/components/TelemetryFacetSidebar.js.map +1 -1
  720. package/build/dist/UI/Components/TelemetryViewer/components/TelemetryFacetValueRow.js +1 -1
  721. package/build/dist/UI/Components/TelemetryViewer/components/TelemetryFacetValueRow.js.map +1 -1
  722. package/build/dist/UI/Components/Tooltip/InfoTooltip.js +28 -0
  723. package/build/dist/UI/Components/Tooltip/InfoTooltip.js.map +1 -0
  724. package/build/dist/UI/Components/Workflow/ColumnEditor/ModelQueryBuilder.js +1 -1
  725. package/build/dist/UI/Components/Workflow/ColumnEditor/ModelQueryBuilder.js.map +1 -1
  726. package/build/dist/UI/Components/Workflow/ComponentsModal.js +2 -2
  727. package/build/dist/UI/Components/Workflow/ComponentsModal.js.map +1 -1
  728. package/build/dist/UI/Components/Workflow/StepTraceViewer.js +1 -1
  729. package/build/dist/UI/Components/Workflow/StepTraceViewer.js.map +1 -1
  730. package/build/dist/UI/Utils/Navigation.js +66 -33
  731. package/build/dist/UI/Utils/Navigation.js.map +1 -1
  732. package/build/dist/UI/Utils/PermissionGate.js +4 -2
  733. package/build/dist/UI/Utils/PermissionGate.js.map +1 -1
  734. package/build/dist/UI/Utils/Telemetry/TelemetryEntityNames.js +7 -0
  735. package/build/dist/UI/Utils/Telemetry/TelemetryEntityNames.js.map +1 -1
  736. package/build/dist/UI/Utils/TelemetryService.js +3 -2
  737. package/build/dist/UI/Utils/TelemetryService.js.map +1 -1
  738. package/build/dist/Utils/Incident/IncidentFromAlerts.js +306 -0
  739. package/build/dist/Utils/Incident/IncidentFromAlerts.js.map +1 -0
  740. package/build/dist/Utils/LabelRuleImportExport.js +2 -0
  741. package/build/dist/Utils/LabelRuleImportExport.js.map +1 -1
  742. package/build/dist/Utils/MetricUnitUtil.js +77 -13
  743. package/build/dist/Utils/MetricUnitUtil.js.map +1 -1
  744. package/build/dist/Utils/Monitor/MetricValueFormatter.js +58 -13
  745. package/build/dist/Utils/Monitor/MetricValueFormatter.js.map +1 -1
  746. package/build/dist/Utils/Monitor/PlatformMetricUnitUtil.js +161 -0
  747. package/build/dist/Utils/Monitor/PlatformMetricUnitUtil.js.map +1 -0
  748. package/build/dist/Utils/Monitor/PlatformResourceIdentity.js +323 -0
  749. package/build/dist/Utils/Monitor/PlatformResourceIdentity.js.map +1 -0
  750. package/build/dist/Utils/NetworkDiscovery/DiscoveredHostNamingDiagnosis.js +270 -0
  751. package/build/dist/Utils/NetworkDiscovery/DiscoveredHostNamingDiagnosis.js.map +1 -0
  752. package/build/dist/Utils/NetworkDiscovery/DiscoveredHostUtil.js +23 -0
  753. package/build/dist/Utils/NetworkDiscovery/DiscoveredHostUtil.js.map +1 -1
  754. package/build/dist/Utils/NetworkDiscovery/NetbiosNameUtil.js +61 -0
  755. package/build/dist/Utils/NetworkDiscovery/NetbiosNameUtil.js.map +1 -1
  756. package/build/dist/Utils/Rum/SessionTraceState.js +154 -0
  757. package/build/dist/Utils/Rum/SessionTraceState.js.map +1 -0
  758. package/build/dist/Utils/Telemetry/DatabaseServerEntityKeys.js +178 -0
  759. package/build/dist/Utils/Telemetry/DatabaseServerEntityKeys.js.map +1 -0
  760. package/build/dist/Utils/Telemetry/EntityKey.js +133 -0
  761. package/build/dist/Utils/Telemetry/EntityKey.js.map +1 -1
  762. package/build/dist/Utils/ValueFormatter.js +15 -0
  763. package/build/dist/Utils/ValueFormatter.js.map +1 -1
  764. package/package.json +1 -1
  765. package/tsconfig.tests.json +7 -5
@@ -0,0 +1,1447 @@
1
+ /*
2
+ * MonitorCriteriaEvaluator reaches the template renderer, which loads the
3
+ * native isolated-vm addon. Nothing here uses the sandbox and the
4
+ * prebuilt binary cannot always dlopen in the test environment.
5
+ */
6
+ jest.mock("isolated-vm", () => {
7
+ return {};
8
+ });
9
+
10
+ import Monitor from "../../../../Models/DatabaseModels/Monitor";
11
+ import MonitorCriteriaEvaluator from "../../../../Server/Utils/Monitor/MonitorCriteriaEvaluator";
12
+ import AggregateModel from "../../../../Types/BaseDatabase/AggregatedModel";
13
+ import AggregatedResult from "../../../../Types/BaseDatabase/AggregatedResult";
14
+ import Dictionary from "../../../../Types/Dictionary";
15
+ import { JSONObject } from "../../../../Types/JSON";
16
+ import MetricQueryConfigData from "../../../../Types/Metrics/MetricQueryConfigData";
17
+ import MetricsAggregationType from "../../../../Types/Metrics/MetricsAggregationType";
18
+ import MetricsViewConfig from "../../../../Types/Metrics/MetricsViewConfig";
19
+ import { FilterType } from "../../../../Types/Monitor/CriteriaFilter";
20
+ import {
21
+ buildKubernetesMonitorConfig,
22
+ buildKubernetesMonitorStep,
23
+ buildOfflineCriteriaInstance,
24
+ buildOnlineCriteriaInstance,
25
+ getKubernetesAlertTemplateById,
26
+ KubernetesAlertTemplate,
27
+ KubernetesAlertTemplateArgs,
28
+ } from "../../../../Types/Monitor/KubernetesAlertTemplates";
29
+ import { getKubernetesMetricByMetricName } from "../../../../Types/Monitor/KubernetesMetricCatalog";
30
+ import MetricCriteriaContext from "../../../../Types/Monitor/MetricMonitor/MetricCriteriaContext";
31
+ import MetricMonitorResponse, {
32
+ KubernetesAffectedResource,
33
+ KubernetesResourceBreakdown,
34
+ } from "../../../../Types/Monitor/MetricMonitor/MetricMonitorResponse";
35
+ import MetricSeriesResult from "../../../../Types/Monitor/MetricMonitor/MetricSeriesResult";
36
+ import MonitorCriteriaInstance from "../../../../Types/Monitor/MonitorCriteriaInstance";
37
+ import MonitorEvaluationSummary from "../../../../Types/Monitor/MonitorEvaluationSummary";
38
+ import MonitorStep from "../../../../Types/Monitor/MonitorStep";
39
+ import { KubernetesResourceScope } from "../../../../Types/Monitor/MonitorStepKubernetesMonitor";
40
+ import MonitorType from "../../../../Types/Monitor/MonitorType";
41
+ import { buildUnhealthyCriteriaInstance } from "../../../../Types/Monitor/Recommendation/RecommendationCriteriaBuilder";
42
+ import ObjectID from "../../../../Types/ObjectID";
43
+ import ProbeApiIngestResponse, {
44
+ MatchedCriteriaResult,
45
+ PerSeriesCriteriaMatch,
46
+ } from "../../../../Types/Probe/ProbeApiIngestResponse";
47
+ import RollingTime from "../../../../Types/RollingTime/RollingTime";
48
+ import PlatformMetricUnitUtil from "../../../../Utils/Monitor/PlatformMetricUnitUtil";
49
+ import PlatformResourceIdentity from "../../../../Utils/Monitor/PlatformResourceIdentity";
50
+ import { describe, expect, test } from "@jest/globals";
51
+
52
+ /*
53
+ * The "Affected Resources" list of a GROUPED Kubernetes monitor is built
54
+ * from the series the matched criteria actually breached, not from the
55
+ * worker's raw datapoint scan. Before that, every ratio template listed
56
+ * the scan of whichever query ran last — the DENOMINATOR, in raw bytes or
57
+ * cores — and every resource in the cluster, breaching or not:
58
+ *
59
+ * Affected Resources (4 total)
60
+ * 1. Node `gke-...-1nd7` — 257760964608
61
+ *
62
+ * These tests drive every shipped grouped Kubernetes template through the
63
+ * public evaluator entry point with the response shape the worker builds
64
+ * (per-series query rows carrying the raw datapoint's attributes, formula
65
+ * rows carrying only the group labels, one tagged raw scan per query, and
66
+ * catalog-overlaid native units) and pin what the email says: which
67
+ * resources are listed, how each is titled, what value — in which unit —
68
+ * it carries, in which order, and what the analysis says about the worst
69
+ * one.
70
+ */
71
+
72
+ const CLUSTER: string = "prod-east";
73
+
74
+ const CLUSTER_KEY: string = "resource.k8s.cluster.name";
75
+ const NODE_KEY: string = "resource.k8s.node.name";
76
+ const NAMESPACE_KEY: string = "resource.k8s.namespace.name";
77
+ const POD_KEY: string = "resource.k8s.pod.name";
78
+ const CONTAINER_KEY: string = "resource.k8s.container.name";
79
+ const DEPLOYMENT_KEY: string = "resource.k8s.deployment.name";
80
+ const HPA_KEY: string = "resource.k8s.hpa.name";
81
+
82
+ const MINUTES: Array<Date> = [0, 1, 2, 3, 4].map((minute: number): Date => {
83
+ return new Date(Date.UTC(2026, 8, 25, 10, minute, 0));
84
+ });
85
+
86
+ /*
87
+ * The units the OpenTelemetry exporters declare for these metrics
88
+ * (MetricType.unit). The worker overlays the Kubernetes catalog on top of
89
+ * them — see PlatformMetricUnitUtil — and so do these tests, by calling
90
+ * the same helper.
91
+ */
92
+ const DECLARED_UNITS: Map<string, string> = new Map<string, string>([
93
+ ["k8s.node.cpu.usage", "{cpu}"],
94
+ ["k8s.node.allocatable_cpu", "{cpu}"],
95
+ ["k8s.node.memory.usage", "By"],
96
+ ["k8s.node.allocatable_memory", "By"],
97
+ ["k8s.node.filesystem.usage", "By"],
98
+ ["k8s.node.filesystem.available", "By"],
99
+ ["k8s.container.cpu_request", "{cpu}"],
100
+ ["k8s.container.memory_request", "By"],
101
+ ["k8s.hpa.current_replicas", "{pod}"],
102
+ ["k8s.hpa.max_replicas", "{pod}"],
103
+ ["k8s.container.restarts", "{restart}"],
104
+ ["k8s.pod.memory_limit_utilization", "1"],
105
+ ["k8s.node.condition_ready", "1"],
106
+ ]);
107
+
108
+ /*
109
+ * ---------------------------------------------------------------------------
110
+ * Monitor step helpers
111
+ * ---------------------------------------------------------------------------
112
+ */
113
+
114
+ function templateArgs(): KubernetesAlertTemplateArgs {
115
+ return {
116
+ clusterIdentifier: CLUSTER,
117
+ onlineMonitorStatusId: ObjectID.generate(),
118
+ offlineMonitorStatusId: ObjectID.generate(),
119
+ defaultIncidentSeverityId: ObjectID.generate(),
120
+ defaultAlertSeverityId: ObjectID.generate(),
121
+ monitorName: "prod-east - Kubernetes",
122
+ };
123
+ }
124
+
125
+ function templateStep(templateId: string): MonitorStep {
126
+ const template: KubernetesAlertTemplate | undefined =
127
+ getKubernetesAlertTemplateById(templateId);
128
+
129
+ if (!template) {
130
+ throw new Error(`${templateId} template missing`);
131
+ }
132
+
133
+ return template.getMonitorStep(templateArgs());
134
+ }
135
+
136
+ function viewConfigOf(step: MonitorStep): MetricsViewConfig {
137
+ const config: MetricsViewConfig | undefined =
138
+ MonitorStep.getMetricsViewConfig(step);
139
+
140
+ if (!config) {
141
+ throw new Error("monitor step has no metric view config");
142
+ }
143
+
144
+ return config;
145
+ }
146
+
147
+ function metricNameOf(query: MetricQueryConfigData): string {
148
+ return (query.metricQueryData?.filterData?.metricName as string) || "";
149
+ }
150
+
151
+ // [firing, recovery] — the order every Kubernetes template builds them in.
152
+ function criteriaOf(step: MonitorStep): {
153
+ firing: MonitorCriteriaInstance;
154
+ recovery: MonitorCriteriaInstance;
155
+ } {
156
+ const instances: Array<MonitorCriteriaInstance> =
157
+ step.data?.monitorCriteria?.data?.monitorCriteriaInstanceArray || [];
158
+
159
+ return { firing: instances[0]!, recovery: instances[1]! };
160
+ }
161
+
162
+ /*
163
+ * A hand-built grouped Kubernetes monitor over one query: what a user gets
164
+ * from the monitor form, rather than from a template card.
165
+ */
166
+ function customGroupedStep(input: {
167
+ metricName: string;
168
+ metricAlias: string;
169
+ aggregationType: MetricsAggregationType;
170
+ groupByAttributeKeys: Array<string>;
171
+ firing: MonitorCriteriaInstance;
172
+ }): MonitorStep {
173
+ const args: KubernetesAlertTemplateArgs = templateArgs();
174
+
175
+ return buildKubernetesMonitorStep({
176
+ kubernetesMonitor: buildKubernetesMonitorConfig({
177
+ clusterIdentifier: CLUSTER,
178
+ metricName: input.metricName,
179
+ metricAlias: input.metricAlias,
180
+ resourceScope: KubernetesResourceScope.Node,
181
+ rollingTime: RollingTime.Past5Minutes,
182
+ aggregationType: input.aggregationType,
183
+ groupByAttributeKeys: input.groupByAttributeKeys,
184
+ }),
185
+ offlineCriteriaInstance: input.firing,
186
+ onlineCriteriaInstance: buildOnlineCriteriaInstance({
187
+ onlineMonitorStatusId: args.onlineMonitorStatusId,
188
+ metricAlias: input.metricAlias,
189
+ filterType: FilterType.LessThanOrEqualTo,
190
+ value: 1,
191
+ }),
192
+ });
193
+ }
194
+
195
+ /*
196
+ * ---------------------------------------------------------------------------
197
+ * Worker response helpers
198
+ * ---------------------------------------------------------------------------
199
+ */
200
+
201
+ /*
202
+ * One series as the worker hands it over: its group-by labels, the
203
+ * attributes every raw datapoint behind it carries on top of those, and a
204
+ * value per minute for each query (and the formula, when there is one) —
205
+ * already in each query's display unit.
206
+ */
207
+ interface SeriesSpec {
208
+ labels: JSONObject;
209
+ datapointAttributes?: JSONObject | undefined;
210
+ queryValues: Array<Array<number>>;
211
+ formulaValues?: Array<number> | undefined;
212
+ }
213
+
214
+ function row(input: {
215
+ timestamp: Date;
216
+ value: number;
217
+ attributes: JSONObject;
218
+ }): AggregateModel {
219
+ return {
220
+ timestamp: input.timestamp,
221
+ value: input.value,
222
+ attributes: input.attributes,
223
+ } as unknown as AggregateModel;
224
+ }
225
+
226
+ function rawAttributesOf(spec: SeriesSpec): JSONObject {
227
+ return {
228
+ [CLUSTER_KEY]: CLUSTER,
229
+ ...(spec.datapointAttributes || {}),
230
+ ...spec.labels,
231
+ };
232
+ }
233
+
234
+ function unitsByMetricNameOf(
235
+ queries: Array<MetricQueryConfigData>,
236
+ ): Dictionary<string> {
237
+ return PlatformMetricUnitUtil.buildUnitsByMetricName({
238
+ platform: "kubernetes",
239
+ metricNames: queries.map(metricNameOf),
240
+ declaredUnitsByMetricName: DECLARED_UNITS,
241
+ });
242
+ }
243
+
244
+ function workerResponse(input: {
245
+ step: MonitorStep;
246
+ series: Array<SeriesSpec>;
247
+ }): MetricMonitorResponse {
248
+ const config: MetricsViewConfig = viewConfigOf(input.step);
249
+ const queries: Array<MetricQueryConfigData> = config.queryConfigs;
250
+ const hasFormula: boolean = config.formulaConfigs.length > 0;
251
+
252
+ /*
253
+ * Aligned [queries..., formulas...]: query rows keep the raw datapoint's
254
+ * full attribute map, formula rows only the group labels.
255
+ */
256
+ const seriesBreakdown: Array<MetricSeriesResult> = input.series.map(
257
+ (spec: SeriesSpec, index: number): MetricSeriesResult => {
258
+ const queryResults: Array<AggregatedResult> = queries.map(
259
+ (_query: MetricQueryConfigData, queryIndex: number) => {
260
+ return {
261
+ data: (spec.queryValues[queryIndex] || []).map(
262
+ (value: number, minute: number): AggregateModel => {
263
+ return row({
264
+ timestamp: MINUTES[minute]!,
265
+ value: value,
266
+ attributes: rawAttributesOf(spec),
267
+ });
268
+ },
269
+ ),
270
+ };
271
+ },
272
+ );
273
+
274
+ const formulaResults: Array<AggregatedResult> = hasFormula
275
+ ? [
276
+ {
277
+ data: (spec.formulaValues || []).map(
278
+ (value: number, minute: number): AggregateModel => {
279
+ return row({
280
+ timestamp: MINUTES[minute]!,
281
+ value: value,
282
+ attributes: { ...spec.labels },
283
+ });
284
+ },
285
+ ),
286
+ },
287
+ ]
288
+ : [];
289
+
290
+ return {
291
+ fingerprint: `fp-${index}`,
292
+ labels: spec.labels,
293
+ aggregatedResults: [...queryResults, ...formulaResults],
294
+ };
295
+ },
296
+ );
297
+
298
+ const unitsByMetricName: Dictionary<string> = unitsByMetricNameOf(queries);
299
+
300
+ /*
301
+ * One raw scan per query, tagged with its alias, in the metric's NATIVE
302
+ * unit (the scan never goes through the display-unit converter) — so a
303
+ * list built from it would show bytes / cores / fractions.
304
+ */
305
+ const breakdowns: Array<KubernetesResourceBreakdown> = queries.map(
306
+ (
307
+ query: MetricQueryConfigData,
308
+ queryIndex: number,
309
+ ): KubernetesResourceBreakdown => {
310
+ const metricName: string = metricNameOf(query);
311
+ const toNative: (value: number) => number =
312
+ query.metricAliasData?.legendUnit === "%"
313
+ ? (value: number): number => {
314
+ return value / 100;
315
+ }
316
+ : (value: number): number => {
317
+ return value;
318
+ };
319
+
320
+ return {
321
+ clusterName: CLUSTER,
322
+ metricName: metricName,
323
+ metricFriendlyName:
324
+ getKubernetesMetricByMetricName(metricName)?.friendlyName ||
325
+ metricName,
326
+ metricAlias: query.metricAliasData?.metricVariable,
327
+ metricUnit: unitsByMetricName[metricName.toLowerCase()],
328
+ attributes: { [CLUSTER_KEY]: CLUSTER },
329
+ affectedResources: input.series
330
+ .filter((spec: SeriesSpec): boolean => {
331
+ return (spec.queryValues[queryIndex] || []).length > 0;
332
+ })
333
+ .map((spec: SeriesSpec): KubernetesAffectedResource => {
334
+ const values: Array<number> =
335
+ spec.queryValues[queryIndex]!.map(toNative);
336
+
337
+ return {
338
+ ...PlatformResourceIdentity.kubernetes(rawAttributesOf(spec)),
339
+ metricValue: Math.max(...values),
340
+ lowestMetricValue: Math.min(...values),
341
+ };
342
+ }),
343
+ };
344
+ },
345
+ );
346
+
347
+ return {
348
+ projectId: ObjectID.generate(),
349
+ monitorId: ObjectID.generate(),
350
+ metricResult: [],
351
+ metricViewConfig: config,
352
+ seriesBreakdown: seriesBreakdown,
353
+ kubernetesResourceBreakdowns: breakdowns,
354
+ nativeUnitsByMetricName: unitsByMetricName,
355
+ };
356
+ }
357
+
358
+ type PercentOf = (numerator: number, denominator: number) => number;
359
+
360
+ const plainRatio: PercentOf = (numerator: number, denominator: number) => {
361
+ return (numerator / denominator) * 100;
362
+ };
363
+
364
+ // k8s-high-disk-usage: used / (used + available) * 100, as `df` reports it.
365
+ const diskUsage: PercentOf = (used: number, available: number) => {
366
+ return (used / (used + available)) * 100;
367
+ };
368
+
369
+ function perMinute(value: number | Array<number>): Array<number> {
370
+ return Array.isArray(value)
371
+ ? value
372
+ : MINUTES.map((): number => {
373
+ return value;
374
+ });
375
+ }
376
+
377
+ /*
378
+ * One series of a two-query ratio template, with the formula row the
379
+ * worker computes from the two query rows.
380
+ */
381
+ function ratioSeries(input: {
382
+ labels: JSONObject;
383
+ numerator: number | Array<number>;
384
+ denominator: number | Array<number>;
385
+ percentOf: PercentOf;
386
+ }): SeriesSpec {
387
+ const numerator: Array<number> = perMinute(input.numerator);
388
+ const denominator: Array<number> = perMinute(input.denominator);
389
+
390
+ return {
391
+ labels: input.labels,
392
+ queryValues: [numerator, denominator],
393
+ formulaValues: numerator.map((value: number, minute: number): number => {
394
+ return input.percentOf(value, denominator[minute]!);
395
+ }),
396
+ };
397
+ }
398
+
399
+ function node(name: string): JSONObject {
400
+ return { [NODE_KEY]: name };
401
+ }
402
+
403
+ /*
404
+ * ---------------------------------------------------------------------------
405
+ * Evaluation + rendered-markdown helpers
406
+ * ---------------------------------------------------------------------------
407
+ */
408
+
409
+ async function evaluate(input: {
410
+ step: MonitorStep;
411
+ response: MetricMonitorResponse;
412
+ }): Promise<ProbeApiIngestResponse> {
413
+ const monitor: Monitor = new Monitor();
414
+ monitor._id = ObjectID.generate().toString();
415
+ monitor.monitorType = MonitorType.Kubernetes;
416
+ monitor.name = "prod-east - Kubernetes";
417
+
418
+ return MonitorCriteriaEvaluator.processMonitorStep({
419
+ dataToProcess: input.response,
420
+ monitorStep: input.step,
421
+ monitor: monitor,
422
+ probeApiIngestResponse: {
423
+ monitorId: monitor.id!,
424
+ rootCause: null,
425
+ },
426
+ evaluationSummary: {
427
+ criteriaResults: [],
428
+ events: [],
429
+ } as unknown as MonitorEvaluationSummary,
430
+ });
431
+ }
432
+
433
+ // The rendered root cause of one matched criteria, or "" when it did not match.
434
+ function rootCauseOf(
435
+ response: ProbeApiIngestResponse,
436
+ criteria: MonitorCriteriaInstance,
437
+ ): string {
438
+ const matched: MatchedCriteriaResult | undefined = (
439
+ response.matchedCriteria || []
440
+ ).find((result: MatchedCriteriaResult): boolean => {
441
+ return result.criteriaId === criteria.data?.id?.toString();
442
+ });
443
+
444
+ return matched?.rootCause || "";
445
+ }
446
+
447
+ async function evaluateFiring(input: {
448
+ step: MonitorStep;
449
+ series: Array<SeriesSpec>;
450
+ }): Promise<string> {
451
+ const response: ProbeApiIngestResponse = await evaluate({
452
+ step: input.step,
453
+ response: workerResponse(input),
454
+ });
455
+
456
+ return rootCauseOf(response, criteriaOf(input.step).firing);
457
+ }
458
+
459
+ // From the "Affected Resources" heading up to the analysis that follows it.
460
+ function affectedResourcesSection(rootCause: string): string {
461
+ const start: number = rootCause.indexOf("**Affected Resources**");
462
+
463
+ if (start < 0) {
464
+ return "";
465
+ }
466
+
467
+ const end: number = rootCause.indexOf("**Root Cause Analysis**", start);
468
+
469
+ return (
470
+ end < 0 ? rootCause.substring(start) : rootCause.substring(start, end)
471
+ ).trim();
472
+ }
473
+
474
+ const ENTRY_HEAD: RegExp = /^\d+\. /;
475
+
476
+ // The first line of every numbered entry in the list.
477
+ function entryHeads(section: string): Array<string> {
478
+ return section.split("\n").filter((line: string): boolean => {
479
+ return ENTRY_HEAD.test(line);
480
+ });
481
+ }
482
+
483
+ /*
484
+ * "Friendly (`metric`)", or just "`metric`" when the catalog has no
485
+ * friendlier name — looked up rather than hard-coded, since the catalog
486
+ * is still growing.
487
+ */
488
+ function describedMetric(metricName: string): string {
489
+ const friendlyName: string = (
490
+ getKubernetesMetricByMetricName(metricName)?.friendlyName || ""
491
+ ).trim();
492
+
493
+ if (!friendlyName || friendlyName === metricName) {
494
+ return `\`${metricName}\``;
495
+ }
496
+
497
+ return `${friendlyName} (\`${metricName}\`)`;
498
+ }
499
+
500
+ const PERCENT_ENTRY: RegExp = / — \*\*\d+\.\d{2}%\*\*$/;
501
+ const LONG_RAW_NUMBER: RegExp = /\b\d{10,}\b/;
502
+ const BOLD_BYTES: RegExp = /\*\*[\d.]+ (B|KB|MB|GB|TB|PB)\*\*/;
503
+
504
+ /*
505
+ * ---------------------------------------------------------------------------
506
+ * 1. Every ratio template
507
+ * ---------------------------------------------------------------------------
508
+ */
509
+
510
+ interface RatioTemplateCase {
511
+ templateId: string;
512
+ resourceNoun: string;
513
+ legend: string;
514
+ expression: string;
515
+ series: Array<SeriesSpec>;
516
+ // Each entry exactly as rendered: its head line, then its detail bullets.
517
+ expectedEntries: Array<string>;
518
+ notListed: Array<string>;
519
+ analysis: Array<string>;
520
+ }
521
+
522
+ const RATIO_TEMPLATE_CASES: Array<RatioTemplateCase> = [
523
+ {
524
+ templateId: "k8s-high-cpu",
525
+ resourceNoun: "nodes",
526
+ legend: "Node CPU Utilization (%)",
527
+ expression: "(used_cpu / alloc_cpu) * 100",
528
+ series: [
529
+ ratioSeries({
530
+ labels: node("node-cpu-a"),
531
+ numerator: [3.64, 3.68, 3.72, 3.76, 3.8],
532
+ denominator: 4,
533
+ percentOf: plainRatio,
534
+ }),
535
+ // One sample at 97.5%, the rest at 50%: not sustained, not affected.
536
+ ratioSeries({
537
+ labels: node("node-cpu-spiky"),
538
+ numerator: [2, 2, 3.9, 2, 2],
539
+ denominator: 4,
540
+ percentOf: plainRatio,
541
+ }),
542
+ ratioSeries({
543
+ labels: node("node-cpu-c"),
544
+ numerator: 1.84,
545
+ denominator: 2,
546
+ percentOf: plainRatio,
547
+ }),
548
+ ratioSeries({
549
+ labels: node("node-cpu-b"),
550
+ numerator: [7.6, 7.68, 7.76, 7.84, 7.92],
551
+ denominator: 8,
552
+ percentOf: plainRatio,
553
+ }),
554
+ ratioSeries({
555
+ labels: node("node-cpu-idle"),
556
+ numerator: 1,
557
+ denominator: 4,
558
+ percentOf: plainRatio,
559
+ }),
560
+ ],
561
+ expectedEntries: [
562
+ "1. **Node** `node-cpu-b` — **99.00%**",
563
+ "2. **Node** `node-cpu-a` — **95.00%**",
564
+ "3. **Node** `node-cpu-c` — **92.00%**",
565
+ ],
566
+ notListed: ["node-cpu-spiky", "node-cpu-idle"],
567
+ analysis: [
568
+ "Node CPU utilization has exceeded the configured threshold.",
569
+ "Node `node-cpu-b` is at **99.00%** CPU utilization.",
570
+ ],
571
+ },
572
+ {
573
+ templateId: "k8s-high-memory",
574
+ resourceNoun: "nodes",
575
+ legend: "Node Memory Utilization (%)",
576
+ expression: "(used_mem / alloc_mem) * 100",
577
+ series: [
578
+ ratioSeries({
579
+ labels: node("node-mem-a"),
580
+ numerator: [
581
+ 13760000000, 14000000000, 14400000000, 14560000000, 14720000000,
582
+ ],
583
+ denominator: 16000000000,
584
+ percentOf: plainRatio,
585
+ }),
586
+ ratioSeries({
587
+ labels: node("node-mem-ok"),
588
+ numerator: 16000000000,
589
+ denominator: 32000000000,
590
+ percentOf: plainRatio,
591
+ }),
592
+ ratioSeries({
593
+ labels: node("node-mem-b"),
594
+ numerator: 56000000000,
595
+ denominator: 64000000000,
596
+ percentOf: plainRatio,
597
+ }),
598
+ ],
599
+ expectedEntries: [
600
+ "1. **Node** `node-mem-a` — **92.00%**",
601
+ "2. **Node** `node-mem-b` — **87.50%**",
602
+ ],
603
+ notListed: ["node-mem-ok"],
604
+ analysis: [
605
+ "Node memory utilization has exceeded the configured threshold.",
606
+ "Node `node-mem-a` memory usage is at **92.00%**.",
607
+ ],
608
+ },
609
+ {
610
+ templateId: "k8s-high-disk-usage",
611
+ resourceNoun: "nodes",
612
+ legend: "Node Disk Usage (%)",
613
+ expression: "(used_disk / (used_disk + avail_disk)) * 100",
614
+ series: [
615
+ ratioSeries({
616
+ labels: node("node-disk-a"),
617
+ numerator: [
618
+ 92000000000, 93000000000, 94000000000, 95000000000, 96000000000,
619
+ ],
620
+ denominator: [
621
+ 8000000000, 7000000000, 6000000000, 5000000000, 4000000000,
622
+ ],
623
+ percentOf: diskUsage,
624
+ }),
625
+ ratioSeries({
626
+ labels: node("node-disk-ok"),
627
+ numerator: 50000000000,
628
+ denominator: 150000000000,
629
+ percentOf: diskUsage,
630
+ }),
631
+ ratioSeries({
632
+ labels: node("node-disk-b"),
633
+ numerator: 182000000000,
634
+ denominator: 18000000000,
635
+ percentOf: diskUsage,
636
+ }),
637
+ ],
638
+ expectedEntries: [
639
+ "1. **Node** `node-disk-a` — **96.00%**",
640
+ "2. **Node** `node-disk-b` — **91.00%**",
641
+ ],
642
+ notListed: ["node-disk-ok"],
643
+ analysis: [
644
+ "Node disk/filesystem usage has exceeded the configured threshold.",
645
+ "Node `node-disk-a` filesystem usage is at **96.00%**.",
646
+ ],
647
+ },
648
+ {
649
+ templateId: "k8s-node-cpu-request-utilization",
650
+ resourceNoun: "nodes",
651
+ legend: "Node CPU Request Utilization (%)",
652
+ expression: "(req_cpu / alloc_cpu) * 100",
653
+ series: [
654
+ ratioSeries({
655
+ labels: node("node-req-a"),
656
+ numerator: 7.44,
657
+ denominator: 8,
658
+ percentOf: plainRatio,
659
+ }),
660
+ ratioSeries({
661
+ labels: node("node-req-ok"),
662
+ numerator: 4,
663
+ denominator: 8,
664
+ percentOf: plainRatio,
665
+ }),
666
+ ratioSeries({
667
+ labels: node("node-req-b"),
668
+ numerator: [15.2, 15.36, 15.52, 15.68, 15.84],
669
+ denominator: 16,
670
+ percentOf: plainRatio,
671
+ }),
672
+ ],
673
+ expectedEntries: [
674
+ "1. **Node** `node-req-b` — **99.00%**",
675
+ "2. **Node** `node-req-a` — **93.00%**",
676
+ ],
677
+ notListed: ["node-req-ok"],
678
+ analysis: [
679
+ "Node CPU Request Utilization (%) (`(req_cpu / alloc_cpu) * 100`) has breached the configured threshold.",
680
+ "Most affected node: `node-req-b` (**99.00%**)",
681
+ ],
682
+ },
683
+ {
684
+ templateId: "k8s-node-memory-request-utilization",
685
+ resourceNoun: "nodes",
686
+ legend: "Node Memory Request Utilization (%)",
687
+ expression: "(req_mem / alloc_mem) * 100",
688
+ series: [
689
+ ratioSeries({
690
+ labels: node("node-mreq-b"),
691
+ numerator: 58240000000,
692
+ denominator: 64000000000,
693
+ percentOf: plainRatio,
694
+ }),
695
+ ratioSeries({
696
+ labels: node("node-mreq-ok"),
697
+ numerator: 16000000000,
698
+ denominator: 32000000000,
699
+ percentOf: plainRatio,
700
+ }),
701
+ ratioSeries({
702
+ labels: node("node-mreq-a"),
703
+ numerator: 30400000000,
704
+ denominator: 32000000000,
705
+ percentOf: plainRatio,
706
+ }),
707
+ ],
708
+ expectedEntries: [
709
+ "1. **Node** `node-mreq-a` — **95.00%**",
710
+ "2. **Node** `node-mreq-b` — **91.00%**",
711
+ ],
712
+ notListed: ["node-mreq-ok"],
713
+ analysis: [
714
+ "Node Memory Request Utilization (%) (`(req_mem / alloc_mem) * 100`) has breached the configured threshold.",
715
+ "Most affected node: `node-mreq-a` (**95.00%**)",
716
+ ],
717
+ },
718
+ {
719
+ templateId: "k8s-hpa-at-max-replicas",
720
+ resourceNoun: "HPAs",
721
+ legend: "HPA Replica Saturation (%)",
722
+ expression: "(current_replicas / max_replicas) * 100",
723
+ series: [
724
+ ratioSeries({
725
+ labels: { [NAMESPACE_KEY]: "search", [HPA_KEY]: "search-api" },
726
+ numerator: 9,
727
+ denominator: 10,
728
+ percentOf: plainRatio,
729
+ }),
730
+ ratioSeries({
731
+ labels: { [NAMESPACE_KEY]: "batch", [HPA_KEY]: "worker" },
732
+ numerator: 5,
733
+ denominator: 20,
734
+ percentOf: plainRatio,
735
+ }),
736
+ ratioSeries({
737
+ labels: { [NAMESPACE_KEY]: "checkout", [HPA_KEY]: "checkout-api" },
738
+ numerator: 10,
739
+ denominator: 10,
740
+ percentOf: plainRatio,
741
+ }),
742
+ // At the ceiling for one sample only.
743
+ ratioSeries({
744
+ labels: { [NAMESPACE_KEY]: "reports", [HPA_KEY]: "reports-api" },
745
+ numerator: [5, 5, 20, 5, 5],
746
+ denominator: 20,
747
+ percentOf: plainRatio,
748
+ }),
749
+ ratioSeries({
750
+ labels: { [NAMESPACE_KEY]: "orders", [HPA_KEY]: "orders-api" },
751
+ numerator: 19,
752
+ denominator: 20,
753
+ percentOf: plainRatio,
754
+ }),
755
+ ],
756
+ expectedEntries: [
757
+ "1. **HorizontalPodAutoscaler** `checkout-api` — **100.00%**\n - Namespace: `checkout`",
758
+ "2. **HorizontalPodAutoscaler** `orders-api` — **95.00%**\n - Namespace: `orders`",
759
+ "3. **HorizontalPodAutoscaler** `search-api` — **90.00%**\n - Namespace: `search`",
760
+ ],
761
+ notListed: ["`worker`", "reports-api"],
762
+ analysis: [
763
+ "HPA Replica Saturation (%) (`(current_replicas / max_replicas) * 100`) has breached the configured threshold.",
764
+ "Most affected HorizontalPodAutoscaler: `checkout-api` (**100.00%**)",
765
+ ],
766
+ },
767
+ ];
768
+
769
+ for (const testCase of RATIO_TEMPLATE_CASES) {
770
+ describe(`Kubernetes grouped ratio template ${testCase.templateId}`, () => {
771
+ const run: () => Promise<{
772
+ step: MonitorStep;
773
+ rootCause: string;
774
+ }> = async (): Promise<{ step: MonitorStep; rootCause: string }> => {
775
+ const step: MonitorStep = templateStep(testCase.templateId);
776
+
777
+ return {
778
+ step: step,
779
+ rootCause: await evaluateFiring({
780
+ step: step,
781
+ series: testCase.series,
782
+ }),
783
+ };
784
+ };
785
+
786
+ test(`lists only the breaching ${testCase.resourceNoun}, worst first, valued in %`, async () => {
787
+ const { rootCause } = await run();
788
+ const section: string = affectedResourcesSection(rootCause);
789
+
790
+ expect(section).toContain(
791
+ `**Affected Resources** (${testCase.expectedEntries.length} total)`,
792
+ );
793
+
794
+ expect(entryHeads(section)).toEqual(
795
+ testCase.expectedEntries.map((entry: string): string => {
796
+ return entry.split("\n")[0]!;
797
+ }),
798
+ );
799
+
800
+ for (const entry of testCase.expectedEntries) {
801
+ expect(section).toContain(entry);
802
+ }
803
+
804
+ for (const head of entryHeads(section)) {
805
+ expect(head).toMatch(PERCENT_ENTRY);
806
+ }
807
+
808
+ for (const name of testCase.notListed) {
809
+ expect(section).not.toContain(name);
810
+ }
811
+
812
+ // No raw operand anywhere — bytes, cores, replica counts.
813
+ expect(rootCause).not.toMatch(LONG_RAW_NUMBER);
814
+ expect(rootCause).not.toMatch(BOLD_BYTES);
815
+ expect(rootCause).not.toContain(" cores**");
816
+ expect(section).not.toContain("overflow");
817
+ expect(section).not.toContain("more affected resources");
818
+ });
819
+
820
+ test("names the formula, its expression and the metric behind each operand", async () => {
821
+ const { step, rootCause } = await run();
822
+ const queries: Array<MetricQueryConfigData> =
823
+ viewConfigOf(step).queryConfigs;
824
+
825
+ const componentLines: Array<string> = queries.map(
826
+ (query: MetricQueryConfigData): string => {
827
+ return ` - \`${query.metricAliasData?.metricVariable}\` = ${describedMetric(metricNameOf(query))}`;
828
+ },
829
+ );
830
+
831
+ expect(rootCause).toContain(
832
+ [
833
+ "**Kubernetes Cluster Details**",
834
+ `- Cluster: ${CLUSTER}`,
835
+ `- Metric: ${testCase.legend}`,
836
+ `- Formula: \`${testCase.expression}\``,
837
+ ...componentLines,
838
+ ].join("\n"),
839
+ );
840
+
841
+ // The numerator or denominator is never presented as THE metric.
842
+ for (const query of queries) {
843
+ expect(rootCause).not.toContain(
844
+ `- Metric: ${describedMetric(metricNameOf(query))}`,
845
+ );
846
+ }
847
+ });
848
+
849
+ test("the analysis names the worst resource at its percentage", async () => {
850
+ const { rootCause } = await run();
851
+
852
+ expect(rootCause).toContain("**Root Cause Analysis**");
853
+
854
+ for (const line of testCase.analysis) {
855
+ expect(rootCause).toContain(line);
856
+ }
857
+
858
+ // Never the generic "Kubernetes metric `k8s....`" line for a formula.
859
+ expect(rootCause).not.toContain("Kubernetes metric `");
860
+ });
861
+ });
862
+ }
863
+
864
+ /*
865
+ * ---------------------------------------------------------------------------
866
+ * 2. Grouped single-query templates
867
+ * ---------------------------------------------------------------------------
868
+ */
869
+
870
+ describe("Kubernetes grouped template k8s-crashloopbackoff", () => {
871
+ const series: Array<SeriesSpec> = [
872
+ {
873
+ labels: {
874
+ [NAMESPACE_KEY]: "search",
875
+ [POD_KEY]: "search-5c4b-abc",
876
+ [CONTAINER_KEY]: "indexer",
877
+ },
878
+ datapointAttributes: {
879
+ [DEPLOYMENT_KEY]: "search",
880
+ [NODE_KEY]: "gke-node-2",
881
+ },
882
+ queryValues: [[6, 6, 6, 6, 6]],
883
+ },
884
+ {
885
+ labels: {
886
+ [NAMESPACE_KEY]: "payments",
887
+ [POD_KEY]: "checkout-7d9f-2xk",
888
+ [CONTAINER_KEY]: "api",
889
+ },
890
+ datapointAttributes: {
891
+ [DEPLOYMENT_KEY]: "checkout",
892
+ [NODE_KEY]: "gke-node-1",
893
+ },
894
+ queryValues: [[6, 6, 7, 7, 7]],
895
+ },
896
+ {
897
+ labels: {
898
+ [NAMESPACE_KEY]: "payments",
899
+ [POD_KEY]: "ledger-66f8-q9z",
900
+ [CONTAINER_KEY]: "ledger",
901
+ },
902
+ datapointAttributes: {
903
+ [DEPLOYMENT_KEY]: "ledger",
904
+ [NODE_KEY]: "gke-node-3",
905
+ },
906
+ queryValues: [[0, 0, 0, 0, 0]],
907
+ },
908
+ ];
909
+
910
+ test("titles each container with its pod and borrows namespace, deployment and node from the datapoint", async () => {
911
+ const rootCause: string = await evaluateFiring({
912
+ step: templateStep("k8s-crashloopbackoff"),
913
+ series: series,
914
+ });
915
+ const section: string = affectedResourcesSection(rootCause);
916
+
917
+ expect(section).toContain("**Affected Resources** (2 total)");
918
+ expect(entryHeads(section)).toEqual([
919
+ "1. **Container** `api` in pod `checkout-7d9f-2xk` — **7**",
920
+ "2. **Container** `indexer` in pod `search-5c4b-abc` — **6**",
921
+ ]);
922
+ expect(section).toContain(
923
+ [
924
+ "1. **Container** `api` in pod `checkout-7d9f-2xk` — **7**",
925
+ " - Namespace: `payments`",
926
+ " - Deployment: `checkout`",
927
+ " - Node: `gke-node-1`",
928
+ ].join("\n"),
929
+ );
930
+ expect(section).toContain(
931
+ [
932
+ "2. **Container** `indexer` in pod `search-5c4b-abc` — **6**",
933
+ " - Namespace: `search`",
934
+ " - Deployment: `search`",
935
+ " - Node: `gke-node-2`",
936
+ ].join("\n"),
937
+ );
938
+
939
+ // The healthy container is not "affected".
940
+ expect(section).not.toContain("ledger");
941
+ });
942
+
943
+ test("names the metric and says how many times the worst container restarted", async () => {
944
+ const rootCause: string = await evaluateFiring({
945
+ step: templateStep("k8s-crashloopbackoff"),
946
+ series: series,
947
+ });
948
+
949
+ expect(rootCause).toContain(
950
+ `- Metric: ${describedMetric("k8s.container.restarts")}`,
951
+ );
952
+ expect(rootCause).not.toContain("- Formula:");
953
+ expect(rootCause).toContain(
954
+ "The container `api` in pod `checkout-7d9f-2xk` has restarted **7** times.",
955
+ );
956
+ expect(rootCause).not.toMatch(LONG_RAW_NUMBER);
957
+ });
958
+ });
959
+
960
+ describe("Kubernetes grouped template k8s-pod-memory-limit-saturation", () => {
961
+ /*
962
+ * The query declares legendUnit "%", so the worker has already converted
963
+ * kubeletstats' 0–1 fraction to 0–100 before the evaluator sees it.
964
+ */
965
+ const series: Array<SeriesSpec> = [
966
+ {
967
+ labels: { [NAMESPACE_KEY]: "payments", [POD_KEY]: "checkout-7d9f-2xk" },
968
+ datapointAttributes: {
969
+ [DEPLOYMENT_KEY]: "checkout",
970
+ [NODE_KEY]: "gke-node-1",
971
+ },
972
+ queryValues: [[91, 92, 93, 92.5, 91.5]],
973
+ },
974
+ {
975
+ labels: { [NAMESPACE_KEY]: "batch", [POD_KEY]: "worker-0" },
976
+ datapointAttributes: { [NODE_KEY]: "gke-node-3" },
977
+ queryValues: [[40, 41, 42, 43, 44]],
978
+ },
979
+ {
980
+ labels: { [NAMESPACE_KEY]: "search", [POD_KEY]: "search-5c4b-abc" },
981
+ datapointAttributes: {
982
+ [DEPLOYMENT_KEY]: "search",
983
+ [NODE_KEY]: "gke-node-2",
984
+ },
985
+ queryValues: [[95.5, 95.5, 95.5, 95.5, 95.5]],
986
+ },
987
+ ];
988
+
989
+ test("lists the saturated pods in % with their namespace, workload and node", async () => {
990
+ const rootCause: string = await evaluateFiring({
991
+ step: templateStep("k8s-pod-memory-limit-saturation"),
992
+ series: series,
993
+ });
994
+ const section: string = affectedResourcesSection(rootCause);
995
+
996
+ expect(section).toContain("**Affected Resources** (2 total)");
997
+ expect(entryHeads(section)).toEqual([
998
+ "1. **Pod** `search-5c4b-abc` — **95.50%**",
999
+ "2. **Pod** `checkout-7d9f-2xk` — **93.00%**",
1000
+ ]);
1001
+ expect(section).toContain(
1002
+ [
1003
+ "2. **Pod** `checkout-7d9f-2xk` — **93.00%**",
1004
+ " - Namespace: `payments`",
1005
+ " - Deployment: `checkout`",
1006
+ " - Node: `gke-node-1`",
1007
+ ].join("\n"),
1008
+ );
1009
+ expect(section).not.toContain("worker-0");
1010
+
1011
+ // Never re-scaled as a fraction ("9300.00%") nor shown as one ("0.93").
1012
+ expect(rootCause).not.toMatch(/\d{4,}\.\d{2}%/);
1013
+ expect(section).not.toContain("**0.9");
1014
+ });
1015
+
1016
+ test("the analysis names the worst pod at its saturation", async () => {
1017
+ const rootCause: string = await evaluateFiring({
1018
+ step: templateStep("k8s-pod-memory-limit-saturation"),
1019
+ series: series,
1020
+ });
1021
+
1022
+ expect(rootCause).toContain(
1023
+ `- Metric: ${describedMetric("k8s.pod.memory_limit_utilization")}`,
1024
+ );
1025
+ expect(rootCause).toContain(
1026
+ "Most affected pod: `search-5c4b-abc` (**95.50%**)",
1027
+ );
1028
+ // Pod-scoped: never answered with the node CPU / memory sentences.
1029
+ expect(rootCause).not.toContain("Node memory utilization");
1030
+ expect(rootCause).not.toContain("CPU utilization.");
1031
+ });
1032
+ });
1033
+
1034
+ describe("Kubernetes grouped template k8s-node-not-ready", () => {
1035
+ const series: Array<SeriesSpec> = [
1036
+ { labels: node("node-up"), queryValues: [[1, 1, 1, 1, 1]] },
1037
+ { labels: node("node-down"), queryValues: [[0, 0, 0, 0, 0]] },
1038
+ ];
1039
+
1040
+ test("lists only the NotReady node, at 0", async () => {
1041
+ const rootCause: string = await evaluateFiring({
1042
+ step: templateStep("k8s-node-not-ready"),
1043
+ series: series,
1044
+ });
1045
+ const section: string = affectedResourcesSection(rootCause);
1046
+
1047
+ expect(section).toBe(
1048
+ "**Affected Resources** (1 total)\n\n1. **Node** `node-down` — **0**",
1049
+ );
1050
+ expect(rootCause).not.toContain("node-up");
1051
+ });
1052
+
1053
+ test("the analysis names the NotReady node, not its Ready peer", async () => {
1054
+ const rootCause: string = await evaluateFiring({
1055
+ step: templateStep("k8s-node-not-ready"),
1056
+ series: series,
1057
+ });
1058
+
1059
+ expect(rootCause).toContain(
1060
+ `- Metric: ${describedMetric("k8s.node.condition_ready")}`,
1061
+ );
1062
+ expect(rootCause).toContain(
1063
+ "Node `node-down` is reporting NotReady (value: 0).",
1064
+ );
1065
+ });
1066
+ });
1067
+
1068
+ /*
1069
+ * ---------------------------------------------------------------------------
1070
+ * 3. Enrichment safety
1071
+ * ---------------------------------------------------------------------------
1072
+ */
1073
+
1074
+ describe("Kubernetes grouped monitor: a node-level sum of container rows", () => {
1075
+ /*
1076
+ * Container CPU requests summed per NODE. Each raw datapoint behind the
1077
+ * sum belongs to some tenant's container, so the breaching sample's
1078
+ * attributes name a pod, container, namespace and deployment that are
1079
+ * not the node's — borrowing them would title the node with an
1080
+ * arbitrary tenant.
1081
+ */
1082
+ function step(): MonitorStep {
1083
+ const args: KubernetesAlertTemplateArgs = templateArgs();
1084
+
1085
+ return customGroupedStep({
1086
+ metricName: "k8s.container.cpu_request",
1087
+ metricAlias: "node_cpu_requests",
1088
+ aggregationType: MetricsAggregationType.Sum,
1089
+ groupByAttributeKeys: [NODE_KEY],
1090
+ firing: buildOfflineCriteriaInstance({
1091
+ offlineMonitorStatusId: args.offlineMonitorStatusId,
1092
+ incidentSeverityId: args.defaultIncidentSeverityId,
1093
+ alertSeverityId: args.defaultAlertSeverityId,
1094
+ monitorName: args.monitorName,
1095
+ metricAlias: "node_cpu_requests",
1096
+ filterType: FilterType.GreaterThan,
1097
+ value: 3,
1098
+ }),
1099
+ });
1100
+ }
1101
+
1102
+ const series: Array<SeriesSpec> = [
1103
+ {
1104
+ labels: node("gke-node-7"),
1105
+ datapointAttributes: {
1106
+ [NAMESPACE_KEY]: "tenant-a",
1107
+ [POD_KEY]: "tenant-a-api-0",
1108
+ [CONTAINER_KEY]: "api",
1109
+ [DEPLOYMENT_KEY]: "tenant-a-api",
1110
+ },
1111
+ queryValues: [[3.5, 3.6, 3.7, 3.8, 3.9]],
1112
+ },
1113
+ {
1114
+ labels: node("gke-node-8"),
1115
+ datapointAttributes: {
1116
+ [NAMESPACE_KEY]: "tenant-b",
1117
+ [POD_KEY]: "tenant-b-web-0",
1118
+ [CONTAINER_KEY]: "web",
1119
+ },
1120
+ queryValues: [[1, 1, 1, 1, 1]],
1121
+ },
1122
+ ];
1123
+
1124
+ test("titles the entry as the node and borrows nothing from the tenant datapoint", async () => {
1125
+ const rootCause: string = await evaluateFiring({
1126
+ step: step(),
1127
+ series: series,
1128
+ });
1129
+ const section: string = affectedResourcesSection(rootCause);
1130
+
1131
+ expect(section).toBe(
1132
+ "**Affected Resources** (1 total)\n\n1. **Node** `gke-node-7` — **3.9 cores**",
1133
+ );
1134
+
1135
+ expect(rootCause).not.toContain("Namespace:");
1136
+ expect(rootCause).not.toContain("Deployment:");
1137
+ expect(rootCause).not.toContain("tenant-a");
1138
+ expect(rootCause).not.toContain("**Container**");
1139
+ expect(rootCause).not.toContain("**Pod**");
1140
+ });
1141
+
1142
+ test("the analysis names the node, not a tenant pod", async () => {
1143
+ const rootCause: string = await evaluateFiring({
1144
+ step: step(),
1145
+ series: series,
1146
+ });
1147
+
1148
+ expect(rootCause).toContain(
1149
+ `- Metric: ${describedMetric("k8s.container.cpu_request")}`,
1150
+ );
1151
+ expect(rootCause).toContain(
1152
+ "Most affected node: `gke-node-7` (**3.9 cores**)",
1153
+ );
1154
+ expect(rootCause).not.toContain("Most affected pod");
1155
+ });
1156
+ });
1157
+
1158
+ /*
1159
+ * ---------------------------------------------------------------------------
1160
+ * 4. More breaching series than the list shows
1161
+ * ---------------------------------------------------------------------------
1162
+ */
1163
+
1164
+ describe("Kubernetes grouped monitor: more than ten breaching series", () => {
1165
+ // 86% .. 97%, in scrambled order, plus one healthy node.
1166
+ const percents: Array<number> = [
1167
+ 90, 86, 97, 88, 93, 91, 87, 95, 89, 96, 92, 94,
1168
+ ];
1169
+ const allocatable: number = 16000000000;
1170
+
1171
+ const series: Array<SeriesSpec> = [
1172
+ ...percents.map((percent: number): SeriesSpec => {
1173
+ return ratioSeries({
1174
+ labels: node(`node-${percent}`),
1175
+ numerator: (allocatable * percent) / 100,
1176
+ denominator: allocatable,
1177
+ percentOf: plainRatio,
1178
+ });
1179
+ }),
1180
+ ratioSeries({
1181
+ labels: node("node-healthy"),
1182
+ numerator: allocatable / 2,
1183
+ denominator: allocatable,
1184
+ percentOf: plainRatio,
1185
+ }),
1186
+ ];
1187
+
1188
+ test("shows the ten worst, counts all twelve, and summarises the rest", async () => {
1189
+ const rootCause: string = await evaluateFiring({
1190
+ step: templateStep("k8s-high-memory"),
1191
+ series: series,
1192
+ });
1193
+ const section: string = affectedResourcesSection(rootCause);
1194
+
1195
+ expect(section).toContain("**Affected Resources** (12 total)");
1196
+
1197
+ const expectedHeads: Array<string> = [
1198
+ 97, 96, 95, 94, 93, 92, 91, 90, 89, 88,
1199
+ ].map((percent: number, index: number): string => {
1200
+ return `${index + 1}. **Node** \`node-${percent}\` — **${percent}.00%**`;
1201
+ });
1202
+
1203
+ expect(entryHeads(section)).toEqual(expectedHeads);
1204
+ expect(section).toContain("*... and 2 more affected resources*");
1205
+
1206
+ // The two least-bad breaching nodes are counted but not shown.
1207
+ expect(section).not.toContain("`node-87`");
1208
+ expect(section).not.toContain("`node-86`");
1209
+ expect(section).not.toContain("node-healthy");
1210
+ expect(rootCause).not.toMatch(LONG_RAW_NUMBER);
1211
+
1212
+ // The analysis still names the worst node.
1213
+ expect(rootCause).toContain(
1214
+ "Node `node-97` memory usage is at **97.00%**.",
1215
+ );
1216
+ });
1217
+ });
1218
+
1219
+ /*
1220
+ * ---------------------------------------------------------------------------
1221
+ * 5. A series that matched with no data
1222
+ * ---------------------------------------------------------------------------
1223
+ */
1224
+
1225
+ type EvaluatorPrivate = {
1226
+ buildKubernetesRootCauseContext: (input: {
1227
+ dataToProcess: unknown;
1228
+ monitorStep: MonitorStep;
1229
+ monitor: Monitor;
1230
+ criteriaInstance?: MonitorCriteriaInstance | undefined;
1231
+ perSeriesMatches?: Array<PerSeriesCriteriaMatch> | undefined;
1232
+ }) => Promise<string | null>;
1233
+ };
1234
+
1235
+ const Evaluator: EvaluatorPrivate =
1236
+ MonitorCriteriaEvaluator as unknown as EvaluatorPrivate;
1237
+
1238
+ describe("Kubernetes grouped monitor: a series that matched with no data", () => {
1239
+ function kubernetesMonitor(): Monitor {
1240
+ const monitor: Monitor = new Monitor();
1241
+ monitor._id = ObjectID.generate().toString();
1242
+ monitor.monitorType = MonitorType.Kubernetes;
1243
+ monitor.name = "prod-east - Kubernetes";
1244
+ return monitor;
1245
+ }
1246
+
1247
+ function formulaContext(
1248
+ breachingValues: Array<number>,
1249
+ ): MetricCriteriaContext {
1250
+ return {
1251
+ metricName: "(used_mem / alloc_mem) * 100",
1252
+ alias: "node_memory_utilization",
1253
+ displayName: "Node Memory Utilization (%)",
1254
+ unit: "%",
1255
+ aggregationType: null,
1256
+ isFormula: true,
1257
+ formulaExpression: "(used_mem / alloc_mem) * 100",
1258
+ filterAttributes: {},
1259
+ groupBy: [],
1260
+ ...(breachingValues.length > 0
1261
+ ? {
1262
+ breachingSamples: breachingValues.map(
1263
+ (value: number, minute: number) => {
1264
+ return {
1265
+ value: value,
1266
+ timestamp: MINUTES[minute]!,
1267
+ attributes: { attributes: {} },
1268
+ };
1269
+ },
1270
+ ),
1271
+ sampleValueRange: {
1272
+ min: Math.min(...breachingValues),
1273
+ max: Math.max(...breachingValues),
1274
+ },
1275
+ }
1276
+ : {}),
1277
+ };
1278
+ }
1279
+
1280
+ function match(input: {
1281
+ nodeName: string;
1282
+ criteriaId: string;
1283
+ breachingValues: Array<number>;
1284
+ }): PerSeriesCriteriaMatch {
1285
+ return {
1286
+ criteriaMetId: input.criteriaId,
1287
+ fingerprint: `fp-${input.nodeName}`,
1288
+ labels: node(input.nodeName),
1289
+ rootCause: "- matched",
1290
+ metricContext: formulaContext(input.breachingValues),
1291
+ };
1292
+ }
1293
+
1294
+ test("renders **no data** for the silent series and sorts it last", async () => {
1295
+ const step: MonitorStep = templateStep("k8s-high-memory");
1296
+ const firing: MonitorCriteriaInstance = criteriaOf(step).firing;
1297
+ const criteriaId: string = firing.data!.id!.toString();
1298
+
1299
+ const context: string | null =
1300
+ await Evaluator.buildKubernetesRootCauseContext({
1301
+ dataToProcess: workerResponse({ step: step, series: [] }),
1302
+ monitorStep: step,
1303
+ monitor: kubernetesMonitor(),
1304
+ criteriaInstance: firing,
1305
+ perSeriesMatches: [
1306
+ match({ nodeName: "node-silent", criteriaId, breachingValues: [] }),
1307
+ match({
1308
+ nodeName: "node-warm",
1309
+ criteriaId,
1310
+ breachingValues: [86.1, 85.5],
1311
+ }),
1312
+ match({
1313
+ nodeName: "node-hot",
1314
+ criteriaId,
1315
+ breachingValues: [88.5, 91.25, 90],
1316
+ }),
1317
+ ],
1318
+ });
1319
+
1320
+ const section: string = affectedResourcesSection(context || "");
1321
+
1322
+ expect(section).toContain("**Affected Resources** (3 total)");
1323
+ expect(entryHeads(section)).toEqual([
1324
+ "1. **Node** `node-hot` — **91.25%**",
1325
+ "2. **Node** `node-warm` — **86.10%**",
1326
+ "3. **Node** `node-silent` — **no data**",
1327
+ ]);
1328
+ });
1329
+
1330
+ test("end to end: a NoDataPolicy-trigger criteria lists the silent node after the breaching one", async () => {
1331
+ const args: KubernetesAlertTemplateArgs = templateArgs();
1332
+
1333
+ const firing: MonitorCriteriaInstance = buildUnhealthyCriteriaInstance({
1334
+ offlineMonitorStatusId: args.offlineMonitorStatusId,
1335
+ incidentSeverityId: args.defaultIncidentSeverityId,
1336
+ alertSeverityId: args.defaultAlertSeverityId,
1337
+ monitorName: args.monitorName,
1338
+ metricAlias: "node_memory",
1339
+ filterType: FilterType.GreaterThan,
1340
+ value: 12000000000,
1341
+ triggerOnNoData: true,
1342
+ });
1343
+
1344
+ const step: MonitorStep = customGroupedStep({
1345
+ metricName: "k8s.node.memory.usage",
1346
+ metricAlias: "node_memory",
1347
+ aggregationType: MetricsAggregationType.Avg,
1348
+ groupByAttributeKeys: [NODE_KEY],
1349
+ firing: firing,
1350
+ });
1351
+
1352
+ const rootCause: string = await evaluateFiring({
1353
+ step: step,
1354
+ series: [
1355
+ { labels: node("node-silent"), queryValues: [[]] },
1356
+ {
1357
+ labels: node("node-full"),
1358
+ queryValues: [
1359
+ [12500000000, 12600000000, 12800000000, 12900000000, 13000000000],
1360
+ ],
1361
+ },
1362
+ {
1363
+ labels: node("node-fine"),
1364
+ queryValues: [
1365
+ [4000000000, 4000000000, 4000000000, 4000000000, 4000000000],
1366
+ ],
1367
+ },
1368
+ ],
1369
+ });
1370
+ const section: string = affectedResourcesSection(rootCause);
1371
+
1372
+ expect(section).toBe(
1373
+ [
1374
+ "**Affected Resources** (2 total)",
1375
+ "",
1376
+ "1. **Node** `node-full` — **13 GB**",
1377
+ "2. **Node** `node-silent` — **no data**",
1378
+ ].join("\n"),
1379
+ );
1380
+ expect(rootCause).not.toMatch(LONG_RAW_NUMBER);
1381
+ });
1382
+ });
1383
+
1384
+ /*
1385
+ * ---------------------------------------------------------------------------
1386
+ * 6. The recovery criteria, evaluated on the same data
1387
+ * ---------------------------------------------------------------------------
1388
+ */
1389
+
1390
+ describe("Kubernetes grouped ratio template k8s-high-memory: recovery criteria", () => {
1391
+ const series: Array<SeriesSpec> = [
1392
+ ratioSeries({
1393
+ labels: node("node-mem-hot"),
1394
+ numerator: 14720000000,
1395
+ denominator: 16000000000,
1396
+ percentOf: plainRatio,
1397
+ }),
1398
+ ratioSeries({
1399
+ labels: node("node-mem-ok"),
1400
+ numerator: 16000000000,
1401
+ denominator: 32000000000,
1402
+ percentOf: plainRatio,
1403
+ }),
1404
+ ratioSeries({
1405
+ labels: node("node-mem-low"),
1406
+ numerator: 16000000000,
1407
+ denominator: 64000000000,
1408
+ percentOf: plainRatio,
1409
+ }),
1410
+ ];
1411
+
1412
+ test("whatever the recovery list shows is valued in % — never bytes", async () => {
1413
+ const step: MonitorStep = templateStep("k8s-high-memory");
1414
+ const { firing, recovery } = criteriaOf(step);
1415
+
1416
+ const response: ProbeApiIngestResponse = await evaluate({
1417
+ step: step,
1418
+ response: workerResponse({ step: step, series: series }),
1419
+ });
1420
+
1421
+ // Both bands fire on a grouped monitor: the hot node, and the two healthy ones.
1422
+ expect(rootCauseOf(response, firing)).toContain(
1423
+ "1. **Node** `node-mem-hot` — **92.00%**",
1424
+ );
1425
+
1426
+ const recoveryRootCause: string = rootCauseOf(response, recovery);
1427
+ const section: string = affectedResourcesSection(recoveryRootCause);
1428
+
1429
+ expect(recoveryRootCause).not.toBe("");
1430
+ expect(section).toContain("**Affected Resources** (2 total)");
1431
+ expect(section).toContain("**Node** `node-mem-ok` — **50.00%**");
1432
+ expect(section).toContain("**Node** `node-mem-low` — **25.00%**");
1433
+ expect(section).not.toContain("node-mem-hot");
1434
+
1435
+ expect(entryHeads(section)).toHaveLength(2);
1436
+ for (const head of entryHeads(section)) {
1437
+ expect(head).toMatch(PERCENT_ENTRY);
1438
+ }
1439
+
1440
+ expect(recoveryRootCause).not.toMatch(LONG_RAW_NUMBER);
1441
+ expect(recoveryRootCause).not.toMatch(BOLD_BYTES);
1442
+ expect(recoveryRootCause).not.toMatch(/memory usage is at \*\*[\d.]+ GB/);
1443
+ expect(recoveryRootCause).toContain(
1444
+ "- Metric: Node Memory Utilization (%)",
1445
+ );
1446
+ });
1447
+ });