@oneuptime/common 14.0.3 → 14.0.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Models/DatabaseModels/Alert.ts +55 -0
- package/Models/DatabaseModels/DatabaseServer.ts +1650 -0
- package/Models/DatabaseModels/DatabaseServerEndpoint.ts +540 -0
- package/Models/DatabaseModels/DatabaseServerFeed.ts +625 -0
- package/Models/DatabaseModels/DatabaseServerLabelRule.ts +514 -0
- package/Models/DatabaseModels/DatabaseServerOwnerRule.ts +596 -0
- package/Models/DatabaseModels/DatabaseServerOwnerTeam.ts +491 -0
- package/Models/DatabaseModels/DatabaseServerOwnerUser.ts +490 -0
- package/Models/DatabaseModels/Incident.ts +55 -0
- package/Models/DatabaseModels/Index.ts +16 -0
- package/Models/DatabaseModels/NetworkDeviceDiscoveryScan.ts +26 -0
- package/Models/DatabaseModels/ScheduledMaintenance.ts +55 -0
- package/Models/DatabaseModels/TelemetryException.ts +2 -0
- package/Models/DatabaseModels/UserProjectSsoConsent.ts +146 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1795000000000-AddDatabaseServerTables.ts +673 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1795100000000-AddUserProjectSsoConsent.ts +51 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +4 -0
- package/Server/Middleware/MultipartFormData.ts +1 -1
- package/Server/Middleware/TelemetryIngest.ts +15 -8
- package/Server/Services/AlertReminderRuleService.ts +100 -24
- package/Server/Services/DatabaseServerEndpointService.ts +895 -0
- package/Server/Services/DatabaseServerFeedService.ts +128 -0
- package/Server/Services/DatabaseServerLabelRuleEngineService.ts +340 -0
- package/Server/Services/DatabaseServerLabelRuleService.ts +14 -0
- package/Server/Services/DatabaseServerOwnerRuleEngineService.ts +425 -0
- package/Server/Services/DatabaseServerOwnerRuleService.ts +14 -0
- package/Server/Services/DatabaseServerOwnerTeamService.ts +180 -0
- package/Server/Services/DatabaseServerOwnerUserService.ts +173 -0
- package/Server/Services/DatabaseServerService.ts +4546 -0
- package/Server/Services/DatabaseService.ts +14 -8
- package/Server/Services/DockerResourceService.ts +43 -2
- package/Server/Services/IncidentReminderRuleService.ts +103 -23
- package/Server/Services/Index.ts +16 -0
- package/Server/Services/InventoryItemService.ts +113 -5
- package/Server/Services/IoTDeviceService.ts +145 -37
- package/Server/Services/MetricService.ts +1 -1
- package/Server/Services/OpenTelemetryIngestService.ts +19 -0
- package/Server/Services/PodmanResourceService.ts +43 -2
- package/Server/Services/ScheduledMaintenanceReminderRuleService.ts +107 -23
- package/Server/Services/ServiceService.ts +1 -1
- package/Server/Services/TelemetryUsageBillingService.ts +29 -2
- package/Server/Services/UserProjectSsoConsentService.ts +74 -0
- package/Server/Services/UserService.ts +14 -1
- package/Server/Types/Database/Permissions/OwnerTableRegistry.ts +18 -0
- package/Server/Types/Database/QueryHelper.ts +84 -2
- package/Server/Utils/AI/Toolbox/MetricTools.ts +13 -2
- package/Server/Utils/AI/Toolbox/ResourceTools.ts +81 -2
- package/Server/Utils/AnalyticsDatabase/StatementGenerator.ts +1 -1
- package/Server/Utils/Database/AffectedResourceRelations.ts +6 -0
- package/Server/Utils/Monitor/Criteria/CompareCriteria.ts +33 -0
- package/Server/Utils/Monitor/Criteria/MetricMonitorCriteria.ts +192 -9
- package/Server/Utils/Monitor/MonitorAlert.ts +28 -1
- package/Server/Utils/Monitor/MonitorCriteriaEvaluator.ts +2264 -755
- package/Server/Utils/Monitor/MonitorIncident.ts +28 -1
- package/Server/Utils/Monitor/MonitorMaintenanceSuppression.ts +268 -6
- package/Server/Utils/Monitor/MonitorResource.ts +47 -11
- package/Server/Utils/Monitor/MonitorResourceContext.ts +1 -0
- package/Server/Utils/Monitor/MonitorStepResourceIdentity.ts +239 -21
- package/Server/Utils/Monitor/PerSeriesResolutionRootCause.ts +43 -0
- package/Server/Utils/Monitor/SeriesResourceLabels.ts +291 -0
- package/Server/Utils/Monitor/SeriesResourceLinker.ts +111 -12
- package/Server/Utils/Rules/RuleRun/RuleRunRegistry.ts +25 -0
- package/Server/Utils/StartServer.ts +26 -6
- package/Server/Utils/TeamMember/ProjectLeaveResourceCleanup.ts +2 -0
- package/Server/Utils/Telemetry/DatabaseEndpointDiscovery.ts +688 -0
- package/Server/Utils/Telemetry/EntityRegistry.ts +5 -1
- package/Server/Utils/Telemetry/LogExceptionExtractor.ts +18 -1
- package/Server/Utils/Telemetry/ResourceEntityFilter.ts +175 -12
- package/Server/Utils/Telemetry/ResourceFacetResolver.ts +12 -0
- package/Server/Utils/Telemetry/ServiceDependencyDiscovery.ts +606 -36
- package/Server/Utils/Telemetry/Telemetry.ts +16 -0
- package/Server/Utils/Telemetry/TelemetryEntity.ts +22 -22
- package/Server/Utils/Telemetry/TelemetryIngestionKeyGuard.ts +16 -10
- package/Tests/App/Accounts/SignedInRedirect.test.tsx +241 -0
- package/Tests/App/AdminDashboard/AdminHeaderSmallScreens.test.tsx +221 -4
- package/Tests/App/Dashboard/AIInsightsResourcePageContext.test.ts +42 -0
- package/Tests/App/Dashboard/AffectedResourcesDisplay.test.tsx +100 -0
- package/Tests/App/Dashboard/AffectedResourcesPicker.test.tsx +86 -0
- package/Tests/App/Dashboard/AffectedResourcesPickerHiddenTypes.test.tsx +2 -0
- package/Tests/App/Dashboard/AffectedResourcesSummaryStep.test.tsx +19 -0
- package/Tests/App/Dashboard/BreadcrumbCoverage.test.tsx +14 -0
- package/Tests/App/Dashboard/CorrelateFilterBuilder.test.tsx +26 -1
- package/Tests/App/Dashboard/DashboardAppSsoError.test.tsx +501 -0
- package/Tests/App/Dashboard/DashboardHeaderRequests.test.tsx +64 -1
- package/Tests/App/Dashboard/DashboardHeaderSmallScreens.test.tsx +178 -18
- package/Tests/App/Dashboard/DashboardMasterPageSsoRedirect.test.tsx +444 -0
- package/Tests/App/Dashboard/DashboardNavBarForeignHiddenRule.test.tsx +573 -0
- package/Tests/App/Dashboard/DatabaseChartAxes.test.tsx +431 -0
- package/Tests/App/Dashboard/DatabaseContainerDetailBadge.test.tsx +249 -0
- package/Tests/App/Dashboard/DatabaseDashboardE2EFixes.test.ts +681 -0
- package/Tests/App/Dashboard/DatabaseDocumentationMarkdown.test.ts +1801 -0
- package/Tests/App/Dashboard/DatabaseFleetSummaryRefresh.test.tsx +280 -0
- package/Tests/App/Dashboard/DatabaseFormHelpers.test.tsx +321 -0
- package/Tests/App/Dashboard/DatabaseMetricMonitorLink.test.tsx +795 -0
- package/Tests/App/Dashboard/DatabaseOverviewHeader.test.tsx +580 -0
- package/Tests/App/Dashboard/DatabaseRecommendationsEngineMetrics.test.ts +270 -0
- package/Tests/App/Dashboard/DatabaseServerComponents.test.tsx +1486 -0
- package/Tests/App/Dashboard/DatabaseServerEngineMetricsFilter.test.ts +223 -0
- package/Tests/App/Dashboard/DatabaseServerPresentation.test.ts +435 -0
- package/Tests/App/Dashboard/DatabaseServerSummary.test.ts +186 -0
- package/Tests/App/Dashboard/DatabaseServerTelemetryQueries.test.ts +1553 -0
- package/Tests/App/Dashboard/DatabaseTableTruncation.test.tsx +326 -0
- package/Tests/App/Dashboard/DatabaseTelemetryScope.test.ts +512 -0
- package/Tests/App/Dashboard/DatabaseTelemetryTabs.test.tsx +774 -0
- package/Tests/App/Dashboard/DatabaseViewLayout.test.tsx +233 -0
- package/Tests/App/Dashboard/DatabaseWorkloadBadge.test.tsx +972 -0
- package/Tests/App/Dashboard/DiscoveryReviewInventoryRefresh.test.tsx +5 -0
- package/Tests/App/Dashboard/DiscoveryReviewUnnamedHostHint.test.tsx +1061 -0
- package/Tests/App/Dashboard/EventOverlayScope.test.ts +147 -0
- package/Tests/App/Dashboard/EventOverlayScopeHook.test.tsx +1 -0
- package/Tests/App/Dashboard/LogsResourceFacetChips.test.tsx +1 -0
- package/Tests/App/Dashboard/MetricsViewerDrillDown.test.tsx +310 -0
- package/Tests/App/Dashboard/MetricsViewerEntityScopedRows.test.tsx +495 -0
- package/Tests/App/Dashboard/MonitorCreateFromMonitorBackedDevice.test.tsx +132 -1
- package/Tests/App/Dashboard/NavigationSearchKeywords.test.tsx +5 -0
- package/Tests/App/Dashboard/NetworkTopologyExplorerSearch.test.tsx +1267 -0
- package/Tests/App/Dashboard/ProductOrientation.test.tsx +4 -3
- package/Tests/App/Dashboard/RecommendationsLoadedContext.test.tsx +349 -0
- package/Tests/App/Dashboard/ResourceArchiveSettings.test.tsx +62 -0
- package/Tests/App/Dashboard/ResourceFeedPageWiring.test.ts +8 -1
- package/Tests/App/Dashboard/ResourceFeedPagesFilterSort.test.tsx +14 -0
- package/Tests/App/Dashboard/ResourceOverviewTileTooltips.test.tsx +4 -1
- package/Tests/App/Dashboard/RumOverviewPage.test.tsx +127 -0
- package/Tests/App/Dashboard/ScheduledMaintenanceOverviewPage.test.tsx +2 -0
- package/Tests/App/Dashboard/ServiceMapDatabaseLink.test.tsx +1085 -0
- package/Tests/App/Dashboard/SiteSearchBox.test.tsx +2110 -0
- package/Tests/App/Dashboard/TelemetryMetricsSignals.test.ts +168 -8
- package/Tests/App/Dashboard/TelemetryResourceRetentionSettings.test.tsx +10 -0
- package/Tests/App/Dashboard/TracesResourceFacets.test.tsx +2 -1
- package/Tests/App/StatusPage/StatusPageHeaderForeignHiddenRule.test.tsx +284 -0
- package/Tests/ClassStrings.ts +178 -0
- package/Tests/Fixtures/MobilePasskeyUser.json +1 -2
- package/Tests/ForeignHiddenRuleGuard.ts +2152 -0
- package/Tests/Models/DatabaseModels/DatabaseServerModels.test.ts +2250 -0
- package/Tests/Models/DatabaseModels/ResourceFeedModels.test.ts +24 -5
- package/Tests/Models/DatabaseModels/StaticRuleCriteriaInheritance.test.ts +4 -2
- package/Tests/RenderedMarkup.ts +518 -0
- package/Tests/ResponsiveVisibility.test.ts +490 -4
- package/Tests/ResponsiveVisibility.ts +505 -52
- package/Tests/Server/Infrastructure/Postgres/AddConfigurableRuleCriteriaMigration.test.ts +3 -0
- package/Tests/Server/Infrastructure/Postgres/AddDatabaseServerTablesMigration.test.ts +541 -0
- package/Tests/Server/Infrastructure/Postgres/AddUserProjectSsoConsentMigration.test.ts +234 -0
- package/Tests/Server/Services/ContainerSnapshotUpsertPostgres.test.ts +319 -0
- package/Tests/Server/Services/CrossProjectRelationWriteGuard.test.ts +13 -0
- package/Tests/Server/Services/DatabaseServerEndpointService.test.ts +2033 -0
- package/Tests/Server/Services/DatabaseServerFeedAndOwnerServices.test.ts +529 -0
- package/Tests/Server/Services/DatabaseServerLifecycle.test.ts +3302 -0
- package/Tests/Server/Services/DatabaseServerRegistries.test.ts +603 -0
- package/Tests/Server/Services/DatabaseServerRuleEngines.test.ts +754 -0
- package/Tests/Server/Services/DatabaseServerService.test.ts +3558 -0
- package/Tests/Server/Services/DatabaseServerSqlPostgres.test.ts +2045 -0
- package/Tests/Server/Services/DatabaseServiceUpdateColumnsIfUnlockedPostgres.test.ts +362 -0
- package/Tests/Server/Services/DatabaseServiceUpdateColumnsIfUnlockedReply.test.ts +210 -0
- package/Tests/Server/Services/HookFreeWriteLengthClamp.test.ts +18 -0
- package/Tests/Server/Services/IncidentAlertSloLinkSurvivesEdit.test.ts +2 -0
- package/Tests/Server/Services/IncomingCallPolicyEscalationRuleTarget.test.ts +225 -0
- package/Tests/Server/Services/InventoryItemDisplayName.test.ts +280 -2
- package/Tests/Server/Services/InventoryUpsertSchemaParity.test.ts +8 -2
- package/Tests/Server/Services/IoTDeviceLatestMetricsPostgres.test.ts +689 -0
- package/Tests/Server/Services/IoTDeviceService.test.ts +379 -0
- package/Tests/Server/Services/LatestMetricsValuesShape.test.ts +360 -0
- package/Tests/Server/Services/LlmModelPriceService.test.ts +402 -0
- package/Tests/Server/Services/MetricServiceAggregate.test.ts +12 -0
- package/Tests/Server/Services/OpenTelemetryResourceRetentionMemo.test.ts +7 -1
- package/Tests/Server/Services/OwnerRowUniqueness.test.ts +61 -9
- package/Tests/Server/Services/ReminderRuleLookupPostgres.test.ts +2250 -0
- package/Tests/Server/Services/ReminderRuleRefreshOpenSubjectsPaging.test.ts +653 -0
- package/Tests/Server/Services/ResourceUpdateLastSeenLivenessFallback.test.ts +68 -20
- package/Tests/Server/Services/SavedViewDefaults.test.ts +325 -0
- package/Tests/Server/Services/StaticRuleCriteriaRuntimeCoverage.test.ts +3 -3
- package/Tests/Server/Services/StatusPageCertificateService.test.ts +169 -0
- package/Tests/Server/Services/TeamComplianceSettingService.test.ts +191 -0
- package/Tests/Server/Services/TelemetryResourceFacetCounting.test.ts +9 -0
- package/Tests/Server/Services/UserProjectSsoConsentPostgres.test.ts +153 -0
- package/Tests/Server/Services/UserProjectSsoConsentService.test.ts +192 -0
- package/Tests/Server/Services/UserServiceFirstMasterAdminElection.test.ts +71 -0
- package/Tests/Server/Services/UserSignupIdTakeoverPostgres.test.ts +238 -0
- package/Tests/Server/Services/WorkspaceNotificationSummaryHelpers.test.ts +592 -0
- package/Tests/Server/Types/Billing/PayAsYouGoMeteredAuthorization.test.ts +3 -0
- package/Tests/Server/Types/Database/EventOverlayScopePostgres.test.ts +1 -0
- package/Tests/Server/Types/Database/FeedEventTypeFilterQuery.test.ts +11 -0
- package/Tests/Server/Types/Database/Permissions/InfrastructureOwnershipScope.test.ts +8 -0
- package/Tests/Server/Types/Database/QueryHelperBooleanForCriteriaBackedRule.test.ts +1094 -0
- package/Tests/Server/Types/Database/QueryHelperSearchAllWords.test.ts +651 -0
- package/Tests/Server/Utils/AI/AlertWriteTools.test.ts +256 -0
- package/Tests/Server/Utils/AI/IncidentWriteTools.test.ts +482 -0
- package/Tests/Server/Utils/AI/ResourceTools.test.ts +134 -0
- package/Tests/Server/Utils/Monitor/Criteria/CompareCriteria.test.ts +54 -0
- package/Tests/Server/Utils/Monitor/Criteria/MetricMonitorCriteria.test.ts +41 -0
- package/Tests/Server/Utils/Monitor/Criteria/MetricMonitorCriteriaAnomalyUnits.test.ts +279 -9
- package/Tests/Server/Utils/Monitor/Criteria/MetricMonitorCriteriaDisplayContext.test.ts +933 -0
- package/Tests/Server/Utils/Monitor/DatabaseMaintenanceSuppression.test.ts +582 -0
- package/Tests/Server/Utils/Monitor/DatabaseServerMonitorLinking.test.ts +753 -0
- package/Tests/Server/Utils/Monitor/MetricDecimalThreshold.test.ts +417 -0
- package/Tests/Server/Utils/Monitor/MonitorActionTimestamps.test.ts +1 -0
- package/Tests/Server/Utils/Monitor/MonitorAlertCriteriaReferences.test.ts +1 -0
- package/Tests/Server/Utils/Monitor/MonitorAlertResourceLinking.test.ts +119 -0
- package/Tests/Server/Utils/Monitor/MonitorCriteriaEvaluator.test.ts +60 -25
- package/Tests/Server/Utils/Monitor/MonitorCriteriaEvaluatorAffectedResourceEdgeCases.test.ts +1815 -0
- package/Tests/Server/Utils/Monitor/MonitorCriteriaEvaluatorKubernetesAffectedResources.test.ts +1447 -0
- package/Tests/Server/Utils/Monitor/MonitorCriteriaEvaluatorKubernetesRatioEmail.test.ts +352 -0
- package/Tests/Server/Utils/Monitor/MonitorCriteriaEvaluatorPlatformMetricUnits.test.ts +717 -0
- package/Tests/Server/Utils/Monitor/MonitorCriteriaEvaluatorPlatformRawScan.test.ts +2125 -0
- package/Tests/Server/Utils/Monitor/MonitorCriteriaEvaluatorPlatformSeriesAffectedResources.test.ts +1288 -0
- package/Tests/Server/Utils/Monitor/MonitorDependencySuppressionCreatorSkip.test.ts +1 -0
- package/Tests/Server/Utils/Monitor/MonitorIncidentCriteriaReferences.test.ts +1 -0
- package/Tests/Server/Utils/Monitor/MonitorIncidentMemberRoleMembership.test.ts +1 -0
- package/Tests/Server/Utils/Monitor/MonitorIncidentResourceLinking.test.ts +88 -0
- package/Tests/Server/Utils/Monitor/MonitorMaintenanceSuppression.test.ts +205 -0
- package/Tests/Server/Utils/Monitor/MonitorResourceContext.test.ts +62 -0
- package/Tests/Server/Utils/Monitor/MonitorResourceDatabaseMaintenance.test.ts +803 -0
- package/Tests/Server/Utils/Monitor/MonitorStepResourceIdentity.test.ts +133 -3
- package/Tests/Server/Utils/Monitor/MonitorSummaryPersistence.test.ts +1 -0
- package/Tests/Server/Utils/Monitor/PerSeriesRecoveryResolution.test.ts +472 -1
- package/Tests/Server/Utils/Monitor/PerSeriesSecondEntityAlerting.test.ts +1 -0
- package/Tests/Server/Utils/Monitor/SeriesResourceLinker.test.ts +236 -2
- package/Tests/Server/Utils/SeriesResourceLabels.test.ts +70 -0
- package/Tests/Server/Utils/StartServerProtobufContentType.test.ts +54 -0
- package/Tests/Server/Utils/Telemetry/DatabaseEndpointDiscovery.test.ts +1895 -0
- package/Tests/Server/Utils/Telemetry/EntityRegistry.test.ts +7 -0
- package/Tests/Server/Utils/Telemetry/LogExceptionExtractorSeverityGate.test.ts +90 -0
- package/Tests/Server/Utils/Telemetry/ResourceEntityFilter.test.ts +570 -0
- package/Tests/Server/Utils/Telemetry/ResourceFacetResolver.test.ts +97 -2
- package/Tests/Server/Utils/Telemetry/ServiceDependencyDiscovery.test.ts +1337 -0
- package/Tests/Server/Utils/Telemetry/TelemetryEntity.test.ts +295 -0
- package/Tests/Types/AI/AIResourceContext.test.ts +30 -0
- package/Tests/Types/BaseDatabase/AggregationType.test.ts +5 -1
- package/Tests/Types/Dashboard/KubernetesDashboardTemplate.test.ts +184 -0
- package/Tests/Types/Dashboard/KubernetesDashboardTemplates.test.ts +107 -0
- package/Tests/Types/DatabaseServer/DatabaseContainerClassifier.test.ts +3644 -0
- package/Tests/Types/DatabaseServer/DatabaseContainerCommand.test.ts +340 -0
- package/Tests/Types/DatabaseServer/DatabaseContainerCommandCorpus.ts +826 -0
- package/Tests/Types/DatabaseServer/DatabaseContainerCommandPostgres.test.ts +150 -0
- package/Tests/Types/DatabaseServer/DatabaseEndpoint.test.ts +2657 -0
- package/Tests/Types/DatabaseServer/DatabaseServerDiscoverySource.test.ts +64 -0
- package/Tests/Types/DatabaseServer/DatabaseServerEntityKeys.test.ts +952 -0
- package/Tests/Types/DatabaseServer/DatabaseServerMetricCatalog.test.ts +1161 -0
- package/Tests/Types/DatabaseServer/DatabaseSystem.test.ts +1514 -0
- package/Tests/Types/DatabaseServer/DatabaseTelemetryResolver.test.ts +1558 -0
- package/Tests/Types/Monitor/CephAlertTemplates.test.ts +255 -6
- package/Tests/Types/Monitor/DatabaseAlertTemplates.test.ts +2254 -0
- package/Tests/Types/Monitor/KubernetesAlertTemplates.test.ts +292 -0
- package/Tests/Types/Monitor/KubernetesMetricCatalog.test.ts +272 -0
- package/Tests/Types/Monitor/Recommendation/MonitorRecommendationCatalog.test.ts +253 -9
- package/Tests/Types/Monitor/Recommendation/MonitorRecommendationCoverage.test.ts +13 -5
- package/Tests/Types/Monitor/Recommendation/MonitorRecommendationNotificationMode.test.ts +4 -2
- package/Tests/Types/Monitor/Recommendation/MonitorRecommendationUtil.test.ts +111 -2
- package/Tests/Types/Monitor/Recommendation/RecommendationCriteriaBuilder.test.ts +61 -0
- package/Tests/Types/Monitor/SeriesContext/SeriesLabelDisplay.test.ts +114 -0
- package/Tests/Types/Monitor/Utils/KubernetesAgentEmittedMetrics.ts +202 -0
- package/Tests/Types/NetworkDevice/DiscoveredHostNamingStatus.test.ts +401 -0
- package/Tests/Types/Telemetry/ResourceEntityFacet.test.ts +4 -1
- package/Tests/Types/Telemetry/ResourceFacetCatalog.test.ts +24 -2
- package/Tests/UI/Components/Card.test.tsx +93 -2
- package/Tests/UI/Components/FeedOptions.test.ts +6 -0
- package/Tests/UI/Components/FeedOptionsButton.test.tsx +8 -1
- package/Tests/UI/Components/ForeignHiddenRuleResilience.test.tsx +1147 -0
- package/Tests/UI/Components/HeaderRightRail.test.tsx +41 -1
- package/Tests/UI/Components/LogsEntityNames.test.ts +16 -1
- package/Tests/UI/Components/LogsFacetSidebarHiddenFacets.test.tsx +7 -3
- package/Tests/UI/Components/ResourceFacetConfigs.test.ts +2 -1
- package/Tests/UI/Components/RuleCriteria/RuleCriteriaModelTable.test.tsx +3 -3
- package/Tests/UI/Components/SrOnlyForeignRule.test.tsx +994 -0
- package/Tests/UI/Components/StatusPage/ResourceListSelection.test.tsx +34 -1
- package/Tests/UI/Components/TelemetryFacetSidebarHiddenFacets.test.tsx +4 -1
- package/Tests/UI/ForeignHiddenRuleGuard.test.ts +1951 -0
- package/Tests/UI/Rum/ChunkLoader.test.ts +76 -0
- package/Tests/UI/Rum/ReplayPlayerChrome.test.tsx +19 -1
- package/Tests/UI/Rum/ReplayRailDetail.test.tsx +53 -0
- package/Tests/UI/Rum/ReplaySignals.test.ts +54 -0
- package/Tests/UI/Rum/ReplayTabSwitcher.test.tsx +19 -1
- package/Tests/UI/TailwindPlayCdnForeignHiddenRule.test.ts +1005 -0
- package/Tests/UI/ThemeGroupHoverReveal.test.ts +847 -0
- package/Tests/UI/Utils/Breadcrumb/fixtures/RealBreadcrumbTrails.ts +70 -0
- package/Tests/UI/Utils/Breadcrumb/fixtures/RealRoutePatterns.ts +21 -0
- package/Tests/UI/Utils/ModelAPISsoRedirect.test.ts +127 -0
- package/Tests/UI/Utils/Navigation.test.ts +102 -0
- package/Tests/UI/Utils/Telemetry/TelemetryEntityNames.test.ts +23 -0
- package/Tests/Utils/Dashboard/KubernetesClusterCpuTileRepair.test.ts +370 -0
- package/Tests/Utils/LabelRuleImportExport.test.ts +5 -0
- package/Tests/Utils/MetricUnitUtil.test.ts +227 -2
- package/Tests/Utils/Monitor/MetricValueFormatter.test.ts +288 -2
- package/Tests/Utils/Monitor/PlatformResourceIdentityAndUnits.test.ts +1559 -0
- package/Tests/Utils/NetworkDiscovery/DiscoveredHostNamingDiagnosis.test.ts +2546 -0
- package/Tests/Utils/NetworkDiscovery/DiscoveredHostUtil.test.ts +315 -0
- package/Tests/Utils/NetworkDiscovery/DiscoveryReverseDnsChain.test.ts +336 -1
- package/Tests/Utils/NetworkDiscovery/NetbiosNameUtil.test.ts +244 -0
- package/Tests/Utils/Rules/MonitorTypeRuleCriteria.test.ts +181 -0
- package/Tests/Utils/ValueFormatter.test.ts +50 -0
- package/Tests/tsconfig.json +16 -0
- package/Types/AI/AIResourceContext.ts +7 -0
- package/Types/BaseDatabase/AggregationType.ts +7 -0
- package/Types/Dashboard/DashboardTemplates.ts +22 -8
- package/Types/DatabaseServer/DatabaseConnectionSpan.ts +77 -0
- package/Types/DatabaseServer/DatabaseContainerClassifier.ts +2068 -0
- package/Types/DatabaseServer/DatabaseContainerCommand.ts +801 -0
- package/Types/DatabaseServer/DatabaseEndpoint.ts +1943 -0
- package/Types/DatabaseServer/DatabaseServerDiscoverySource.ts +68 -0
- package/Types/DatabaseServer/DatabaseServerMetricCatalog.ts +966 -0
- package/Types/DatabaseServer/DatabaseSystem.ts +2124 -0
- package/Types/DatabaseServer/DatabaseTelemetryResolver.ts +555 -0
- package/Types/Email/EmailTemplateType.ts +1 -0
- package/Types/Monitor/CephAlertTemplates.ts +18 -0
- package/Types/Monitor/DatabaseAlertTemplates.ts +2020 -0
- package/Types/Monitor/KubernetesAlertTemplates.ts +64 -24
- package/Types/Monitor/KubernetesMetricCatalog.ts +118 -19
- package/Types/Monitor/MetricMonitor/MetricCriteriaContext.ts +14 -0
- package/Types/Monitor/MetricMonitor/MetricMonitorResponse.ts +93 -10
- package/Types/Monitor/Recommendation/MonitorRecommendationCatalog.ts +109 -8
- package/Types/Monitor/Recommendation/MonitorRecommendationTypes.ts +36 -7
- package/Types/Monitor/Recommendation/MonitorRecommendationUtil.ts +43 -2
- package/Types/Monitor/Recommendation/RecommendationCriteriaBuilder.ts +41 -6
- package/Types/Monitor/SeriesContext/SeriesLabelDisplay.ts +26 -0
- package/Types/NetworkDevice/DiscoveredHostNamingStatus.ts +147 -0
- package/Types/Permission.ts +267 -0
- package/Types/Probe/ProbeApiIngestResponse.ts +8 -0
- package/Types/Rules/RuleCriteriaFieldRegistry.ts +10 -0
- package/Types/Rules/RuleRun.ts +12 -0
- package/Types/Rum/SessionReplayCustomEvents.ts +29 -3
- package/Types/Rum/WebVitals.ts +13 -0
- package/Types/Telemetry/EntityType.ts +23 -0
- package/Types/Telemetry/ResourceFacetCatalog.ts +14 -0
- package/Types/Telemetry/ServiceType.ts +8 -0
- package/UI/Components/Banner/Banner.tsx +1 -1
- package/UI/Components/Card/Card.tsx +1 -1
- package/UI/Components/Charts/ChartGroup/ChartGroup.tsx +2 -2
- package/UI/Components/Charts/Line/LineChart.tsx +7 -0
- package/UI/Components/CommandPalette/CommandPalette.tsx +1 -1
- package/UI/Components/Date/StartAndEndDate.tsx +5 -5
- package/UI/Components/Diagram/HorizontalStepChain.tsx +1 -1
- package/UI/Components/Feed/FeedOptionsButton.tsx +1 -1
- package/UI/Components/Forms/BasicForm.tsx +1 -1
- package/UI/Components/Header/Header.tsx +1 -1
- package/UI/Components/Header/HeaderIconDropdownButton.tsx +1 -1
- package/UI/Components/HeaderAlert/HeaderAlert.tsx +1 -1
- package/UI/Components/Input/Input.tsx +11 -0
- package/UI/Components/LogsViewer/components/FacetValueRow.tsx +1 -1
- package/UI/Components/LogsViewer/components/LogsFacetSidebar.tsx +1 -1
- package/UI/Components/Modal/ModalFooter.tsx +1 -1
- package/UI/Components/ModelDetail/CardModelDetail.tsx +2 -2
- package/UI/Components/ModelTable/BaseModelTable.tsx +4 -4
- package/UI/Components/Navbar/NavBar.tsx +9 -2
- package/UI/Components/Navbar/NavBarMenuModal.tsx +2 -2
- package/UI/Components/Page/Page.tsx +1 -1
- package/UI/Components/Pagination/Pagination.tsx +3 -3
- package/UI/Components/ProgressButtons/ProgressButtonItem.tsx +1 -1
- package/UI/Components/SideMenu/SideMenu.tsx +4 -1
- package/UI/Components/StatusPage/ResourceGroupNavigator.tsx +4 -2
- package/UI/Components/StatusPage/ResourceList.tsx +6 -6
- package/UI/Components/TelemetryViewer/components/TelemetryFacetSidebar.tsx +1 -1
- package/UI/Components/TelemetryViewer/components/TelemetryFacetValueRow.tsx +1 -1
- package/UI/Components/Workflow/ColumnEditor/ModelQueryBuilder.tsx +1 -1
- package/UI/Components/Workflow/ComponentsModal.tsx +2 -2
- package/UI/Components/Workflow/StepTraceViewer.tsx +1 -1
- package/UI/Styles/Theme.css +8 -1
- package/UI/Utils/Navigation.ts +89 -42
- package/UI/Utils/Telemetry/TelemetryEntityNames.ts +7 -0
- package/UI/Utils/TelemetryService.ts +4 -3
- package/Utils/Dashboard/KubernetesClusterCpuTileRepair.ts +147 -0
- package/Utils/LabelRuleImportExport.ts +2 -0
- package/Utils/MetricUnitUtil.ts +103 -11
- package/Utils/Monitor/MetricValueFormatter.ts +66 -13
- package/Utils/Monitor/PlatformMetricUnitUtil.ts +215 -0
- package/Utils/Monitor/PlatformResourceIdentity.ts +514 -0
- package/Utils/NetworkDiscovery/DiscoveredHostNamingDiagnosis.ts +425 -0
- package/Utils/NetworkDiscovery/DiscoveredHostUtil.ts +32 -0
- package/Utils/NetworkDiscovery/NetbiosNameUtil.ts +73 -0
- package/Utils/Telemetry/DatabaseServerEntityKeys.ts +275 -0
- package/Utils/Telemetry/EntityKey.ts +176 -0
- package/Utils/ValueFormatter.ts +16 -0
- package/build/dist/Models/DatabaseModels/Alert.js +54 -0
- package/build/dist/Models/DatabaseModels/Alert.js.map +1 -1
- package/build/dist/Models/DatabaseModels/DatabaseServer.js +1683 -0
- package/build/dist/Models/DatabaseModels/DatabaseServer.js.map +1 -0
- package/build/dist/Models/DatabaseModels/DatabaseServerEndpoint.js +559 -0
- package/build/dist/Models/DatabaseModels/DatabaseServerEndpoint.js.map +1 -0
- package/build/dist/Models/DatabaseModels/DatabaseServerFeed.js +648 -0
- package/build/dist/Models/DatabaseModels/DatabaseServerFeed.js.map +1 -0
- package/build/dist/Models/DatabaseModels/DatabaseServerLabelRule.js +522 -0
- package/build/dist/Models/DatabaseModels/DatabaseServerLabelRule.js.map +1 -0
- package/build/dist/Models/DatabaseModels/DatabaseServerOwnerRule.js +603 -0
- package/build/dist/Models/DatabaseModels/DatabaseServerOwnerRule.js.map +1 -0
- package/build/dist/Models/DatabaseModels/DatabaseServerOwnerTeam.js +506 -0
- package/build/dist/Models/DatabaseModels/DatabaseServerOwnerTeam.js.map +1 -0
- package/build/dist/Models/DatabaseModels/DatabaseServerOwnerUser.js +505 -0
- package/build/dist/Models/DatabaseModels/DatabaseServerOwnerUser.js.map +1 -0
- package/build/dist/Models/DatabaseModels/Incident.js +54 -0
- package/build/dist/Models/DatabaseModels/Incident.js.map +1 -1
- package/build/dist/Models/DatabaseModels/Index.js +16 -0
- package/build/dist/Models/DatabaseModels/Index.js.map +1 -1
- package/build/dist/Models/DatabaseModels/NetworkDeviceDiscoveryScan.js.map +1 -1
- package/build/dist/Models/DatabaseModels/ScheduledMaintenance.js +54 -0
- package/build/dist/Models/DatabaseModels/ScheduledMaintenance.js.map +1 -1
- package/build/dist/Models/DatabaseModels/TelemetryException.js +2 -0
- package/build/dist/Models/DatabaseModels/TelemetryException.js.map +1 -1
- package/build/dist/Models/DatabaseModels/UserProjectSsoConsent.js +162 -0
- package/build/dist/Models/DatabaseModels/UserProjectSsoConsent.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1795000000000-AddDatabaseServerTables.js +240 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1795000000000-AddDatabaseServerTables.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1795100000000-AddUserProjectSsoConsent.js +26 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1795100000000-AddUserProjectSsoConsent.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +4 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
- package/build/dist/Server/Middleware/MultipartFormData.js +1 -1
- package/build/dist/Server/Middleware/TelemetryIngest.js +15 -8
- package/build/dist/Server/Middleware/TelemetryIngest.js.map +1 -1
- package/build/dist/Server/Services/AlertReminderRuleService.js +72 -23
- package/build/dist/Server/Services/AlertReminderRuleService.js.map +1 -1
- package/build/dist/Server/Services/DatabaseServerEndpointService.js +694 -0
- package/build/dist/Server/Services/DatabaseServerEndpointService.js.map +1 -0
- package/build/dist/Server/Services/DatabaseServerFeedService.js +110 -0
- package/build/dist/Server/Services/DatabaseServerFeedService.js.map +1 -0
- package/build/dist/Server/Services/DatabaseServerLabelRuleEngineService.js +272 -0
- package/build/dist/Server/Services/DatabaseServerLabelRuleEngineService.js.map +1 -0
- package/build/dist/Server/Services/DatabaseServerLabelRuleService.js +13 -0
- package/build/dist/Server/Services/DatabaseServerLabelRuleService.js.map +1 -0
- package/build/dist/Server/Services/DatabaseServerOwnerRuleEngineService.js +340 -0
- package/build/dist/Server/Services/DatabaseServerOwnerRuleEngineService.js.map +1 -0
- package/build/dist/Server/Services/DatabaseServerOwnerRuleService.js +13 -0
- package/build/dist/Server/Services/DatabaseServerOwnerRuleService.js.map +1 -0
- package/build/dist/Server/Services/DatabaseServerOwnerTeamService.js +160 -0
- package/build/dist/Server/Services/DatabaseServerOwnerTeamService.js.map +1 -0
- package/build/dist/Server/Services/DatabaseServerOwnerUserService.js +153 -0
- package/build/dist/Server/Services/DatabaseServerOwnerUserService.js.map +1 -0
- package/build/dist/Server/Services/DatabaseServerService.js +3272 -0
- package/build/dist/Server/Services/DatabaseServerService.js.map +1 -0
- package/build/dist/Server/Services/DatabaseService.js +8 -4
- package/build/dist/Server/Services/DatabaseService.js.map +1 -1
- package/build/dist/Server/Services/DockerResourceService.js +30 -3
- package/build/dist/Server/Services/DockerResourceService.js.map +1 -1
- package/build/dist/Server/Services/IncidentReminderRuleService.js +73 -23
- package/build/dist/Server/Services/IncidentReminderRuleService.js.map +1 -1
- package/build/dist/Server/Services/Index.js +16 -0
- package/build/dist/Server/Services/Index.js.map +1 -1
- package/build/dist/Server/Services/InventoryItemService.js +88 -5
- package/build/dist/Server/Services/InventoryItemService.js.map +1 -1
- package/build/dist/Server/Services/IoTDeviceService.js +111 -24
- package/build/dist/Server/Services/IoTDeviceService.js.map +1 -1
- package/build/dist/Server/Services/MetricService.js +1 -1
- package/build/dist/Server/Services/OpenTelemetryIngestService.js +24 -9
- package/build/dist/Server/Services/OpenTelemetryIngestService.js.map +1 -1
- package/build/dist/Server/Services/PodmanResourceService.js +30 -3
- package/build/dist/Server/Services/PodmanResourceService.js.map +1 -1
- package/build/dist/Server/Services/ScheduledMaintenanceReminderRuleService.js +75 -23
- package/build/dist/Server/Services/ScheduledMaintenanceReminderRuleService.js.map +1 -1
- package/build/dist/Server/Services/ServiceService.js +1 -1
- package/build/dist/Server/Services/ServiceService.js.map +1 -1
- package/build/dist/Server/Services/TelemetryUsageBillingService.js +23 -2
- package/build/dist/Server/Services/TelemetryUsageBillingService.js.map +1 -1
- package/build/dist/Server/Services/UserProjectSsoConsentService.js +79 -0
- package/build/dist/Server/Services/UserProjectSsoConsentService.js.map +1 -0
- package/build/dist/Server/Services/UserService.js +13 -1
- package/build/dist/Server/Services/UserService.js.map +1 -1
- package/build/dist/Server/Types/Database/Permissions/OwnerTableRegistry.js +18 -0
- package/build/dist/Server/Types/Database/Permissions/OwnerTableRegistry.js.map +1 -1
- package/build/dist/Server/Types/Database/QueryHelper.js +73 -2
- package/build/dist/Server/Types/Database/QueryHelper.js.map +1 -1
- package/build/dist/Server/Utils/AI/Toolbox/MetricTools.js +13 -2
- package/build/dist/Server/Utils/AI/Toolbox/MetricTools.js.map +1 -1
- package/build/dist/Server/Utils/AI/Toolbox/ResourceTools.js +58 -1
- package/build/dist/Server/Utils/AI/Toolbox/ResourceTools.js.map +1 -1
- package/build/dist/Server/Utils/AnalyticsDatabase/StatementGenerator.js +1 -1
- package/build/dist/Server/Utils/Database/AffectedResourceRelations.js +6 -0
- package/build/dist/Server/Utils/Database/AffectedResourceRelations.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/Criteria/CompareCriteria.js +31 -0
- package/build/dist/Server/Utils/Monitor/Criteria/CompareCriteria.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/Criteria/MetricMonitorCriteria.js +135 -14
- package/build/dist/Server/Utils/Monitor/Criteria/MetricMonitorCriteria.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorAlert.js +22 -6
- package/build/dist/Server/Utils/Monitor/MonitorAlert.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorCriteriaEvaluator.js +1489 -524
- package/build/dist/Server/Utils/Monitor/MonitorCriteriaEvaluator.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorIncident.js +22 -6
- package/build/dist/Server/Utils/Monitor/MonitorIncident.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorMaintenanceSuppression.js +196 -6
- package/build/dist/Server/Utils/Monitor/MonitorMaintenanceSuppression.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorResource.js +36 -9
- package/build/dist/Server/Utils/Monitor/MonitorResource.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorResourceContext.js +1 -0
- package/build/dist/Server/Utils/Monitor/MonitorResourceContext.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorStepResourceIdentity.js +175 -17
- package/build/dist/Server/Utils/Monitor/MonitorStepResourceIdentity.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/PerSeriesResolutionRootCause.js +29 -0
- package/build/dist/Server/Utils/Monitor/PerSeriesResolutionRootCause.js.map +1 -0
- package/build/dist/Server/Utils/Monitor/SeriesResourceLabels.js +211 -0
- package/build/dist/Server/Utils/Monitor/SeriesResourceLabels.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/SeriesResourceLinker.js +82 -10
- package/build/dist/Server/Utils/Monitor/SeriesResourceLinker.js.map +1 -1
- package/build/dist/Server/Utils/Rules/RuleRun/RuleRunRegistry.js +25 -0
- package/build/dist/Server/Utils/Rules/RuleRun/RuleRunRegistry.js.map +1 -1
- package/build/dist/Server/Utils/StartServer.js +20 -4
- package/build/dist/Server/Utils/StartServer.js.map +1 -1
- package/build/dist/Server/Utils/TeamMember/ProjectLeaveResourceCleanup.js +2 -0
- package/build/dist/Server/Utils/TeamMember/ProjectLeaveResourceCleanup.js.map +1 -1
- package/build/dist/Server/Utils/Telemetry/DatabaseEndpointDiscovery.js +442 -0
- package/build/dist/Server/Utils/Telemetry/DatabaseEndpointDiscovery.js.map +1 -0
- package/build/dist/Server/Utils/Telemetry/EntityRegistry.js +5 -1
- package/build/dist/Server/Utils/Telemetry/EntityRegistry.js.map +1 -1
- package/build/dist/Server/Utils/Telemetry/LogExceptionExtractor.js +15 -1
- package/build/dist/Server/Utils/Telemetry/LogExceptionExtractor.js.map +1 -1
- package/build/dist/Server/Utils/Telemetry/ResourceEntityFilter.js +121 -5
- package/build/dist/Server/Utils/Telemetry/ResourceEntityFilter.js.map +1 -1
- package/build/dist/Server/Utils/Telemetry/ResourceFacetResolver.js +12 -0
- package/build/dist/Server/Utils/Telemetry/ResourceFacetResolver.js.map +1 -1
- package/build/dist/Server/Utils/Telemetry/ServiceDependencyDiscovery.js +438 -36
- package/build/dist/Server/Utils/Telemetry/ServiceDependencyDiscovery.js.map +1 -1
- package/build/dist/Server/Utils/Telemetry/Telemetry.js +12 -0
- package/build/dist/Server/Utils/Telemetry/Telemetry.js.map +1 -1
- package/build/dist/Server/Utils/Telemetry/TelemetryEntity.js +17 -18
- package/build/dist/Server/Utils/Telemetry/TelemetryEntity.js.map +1 -1
- package/build/dist/Server/Utils/Telemetry/TelemetryIngestionKeyGuard.js +16 -10
- package/build/dist/Server/Utils/Telemetry/TelemetryIngestionKeyGuard.js.map +1 -1
- package/build/dist/Types/AI/AIResourceContext.js +7 -0
- package/build/dist/Types/AI/AIResourceContext.js.map +1 -1
- package/build/dist/Types/BaseDatabase/AggregationType.js +7 -0
- package/build/dist/Types/BaseDatabase/AggregationType.js.map +1 -1
- package/build/dist/Types/Dashboard/DashboardTemplates.js +22 -8
- package/build/dist/Types/Dashboard/DashboardTemplates.js.map +1 -1
- package/build/dist/Types/DatabaseServer/DatabaseConnectionSpan.js +71 -0
- package/build/dist/Types/DatabaseServer/DatabaseConnectionSpan.js.map +1 -0
- package/build/dist/Types/DatabaseServer/DatabaseContainerClassifier.js +1462 -0
- package/build/dist/Types/DatabaseServer/DatabaseContainerClassifier.js.map +1 -0
- package/build/dist/Types/DatabaseServer/DatabaseContainerCommand.js +691 -0
- package/build/dist/Types/DatabaseServer/DatabaseContainerCommand.js.map +1 -0
- package/build/dist/Types/DatabaseServer/DatabaseEndpoint.js +1407 -0
- package/build/dist/Types/DatabaseServer/DatabaseEndpoint.js.map +1 -0
- package/build/dist/Types/DatabaseServer/DatabaseServerDiscoverySource.js +60 -0
- package/build/dist/Types/DatabaseServer/DatabaseServerDiscoverySource.js.map +1 -0
- package/build/dist/Types/DatabaseServer/DatabaseServerMetricCatalog.js +804 -0
- package/build/dist/Types/DatabaseServer/DatabaseServerMetricCatalog.js.map +1 -0
- package/build/dist/Types/DatabaseServer/DatabaseSystem.js +1860 -0
- package/build/dist/Types/DatabaseServer/DatabaseSystem.js.map +1 -0
- package/build/dist/Types/DatabaseServer/DatabaseTelemetryResolver.js +406 -0
- package/build/dist/Types/DatabaseServer/DatabaseTelemetryResolver.js.map +1 -0
- package/build/dist/Types/Email/EmailTemplateType.js +1 -0
- package/build/dist/Types/Email/EmailTemplateType.js.map +1 -1
- package/build/dist/Types/Monitor/CephAlertTemplates.js +18 -0
- package/build/dist/Types/Monitor/CephAlertTemplates.js.map +1 -1
- package/build/dist/Types/Monitor/DatabaseAlertTemplates.js +1518 -0
- package/build/dist/Types/Monitor/DatabaseAlertTemplates.js.map +1 -0
- package/build/dist/Types/Monitor/KubernetesAlertTemplates.js +57 -24
- package/build/dist/Types/Monitor/KubernetesAlertTemplates.js.map +1 -1
- package/build/dist/Types/Monitor/KubernetesMetricCatalog.js +104 -18
- package/build/dist/Types/Monitor/KubernetesMetricCatalog.js.map +1 -1
- package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationCatalog.js +80 -3
- package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationCatalog.js.map +1 -1
- package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationTypes.js +10 -3
- package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationTypes.js.map +1 -1
- package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationUtil.js +29 -0
- package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationUtil.js.map +1 -1
- package/build/dist/Types/Monitor/Recommendation/RecommendationCriteriaBuilder.js +21 -6
- package/build/dist/Types/Monitor/Recommendation/RecommendationCriteriaBuilder.js.map +1 -1
- package/build/dist/Types/Monitor/SeriesContext/SeriesLabelDisplay.js +25 -0
- package/build/dist/Types/Monitor/SeriesContext/SeriesLabelDisplay.js.map +1 -1
- package/build/dist/Types/NetworkDevice/DiscoveredHostNamingStatus.js +136 -0
- package/build/dist/Types/NetworkDevice/DiscoveredHostNamingStatus.js.map +1 -0
- package/build/dist/Types/Permission.js +234 -0
- package/build/dist/Types/Permission.js.map +1 -1
- package/build/dist/Types/Rules/RuleCriteriaFieldRegistry.js +10 -0
- package/build/dist/Types/Rules/RuleCriteriaFieldRegistry.js.map +1 -1
- package/build/dist/Types/Rules/RuleRun.js +4 -0
- package/build/dist/Types/Rules/RuleRun.js.map +1 -1
- package/build/dist/Types/Rum/SessionReplayCustomEvents.js.map +1 -1
- package/build/dist/Types/Rum/WebVitals.js +12 -0
- package/build/dist/Types/Rum/WebVitals.js.map +1 -1
- package/build/dist/Types/Telemetry/EntityType.js +23 -0
- package/build/dist/Types/Telemetry/EntityType.js.map +1 -1
- package/build/dist/Types/Telemetry/ResourceFacetCatalog.js +14 -0
- package/build/dist/Types/Telemetry/ResourceFacetCatalog.js.map +1 -1
- package/build/dist/Types/Telemetry/ServiceType.js +8 -0
- package/build/dist/Types/Telemetry/ServiceType.js.map +1 -1
- package/build/dist/UI/Components/Banner/Banner.js +1 -1
- package/build/dist/UI/Components/Banner/Banner.js.map +1 -1
- package/build/dist/UI/Components/Card/Card.js +1 -1
- package/build/dist/UI/Components/Card/Card.js.map +1 -1
- package/build/dist/UI/Components/Charts/ChartGroup/ChartGroup.js +2 -2
- package/build/dist/UI/Components/Charts/ChartGroup/ChartGroup.js.map +1 -1
- package/build/dist/UI/Components/Charts/Line/LineChart.js +1 -1
- package/build/dist/UI/Components/Charts/Line/LineChart.js.map +1 -1
- package/build/dist/UI/Components/CommandPalette/CommandPalette.js +1 -1
- package/build/dist/UI/Components/CommandPalette/CommandPalette.js.map +1 -1
- package/build/dist/UI/Components/Date/StartAndEndDate.js +5 -5
- package/build/dist/UI/Components/Date/StartAndEndDate.js.map +1 -1
- package/build/dist/UI/Components/Diagram/HorizontalStepChain.js +1 -1
- package/build/dist/UI/Components/Diagram/HorizontalStepChain.js.map +1 -1
- package/build/dist/UI/Components/Feed/FeedOptionsButton.js +1 -1
- package/build/dist/UI/Components/Feed/FeedOptionsButton.js.map +1 -1
- package/build/dist/UI/Components/Forms/BasicForm.js +1 -1
- package/build/dist/UI/Components/Forms/BasicForm.js.map +1 -1
- package/build/dist/UI/Components/Header/HeaderIconDropdownButton.js +1 -1
- package/build/dist/UI/Components/Header/HeaderIconDropdownButton.js.map +1 -1
- package/build/dist/UI/Components/HeaderAlert/HeaderAlert.js +1 -1
- package/build/dist/UI/Components/HeaderAlert/HeaderAlert.js.map +1 -1
- package/build/dist/UI/Components/Input/Input.js +1 -1
- package/build/dist/UI/Components/Input/Input.js.map +1 -1
- package/build/dist/UI/Components/LogsViewer/components/FacetValueRow.js +1 -1
- package/build/dist/UI/Components/LogsViewer/components/FacetValueRow.js.map +1 -1
- package/build/dist/UI/Components/LogsViewer/components/LogsFacetSidebar.js +1 -1
- package/build/dist/UI/Components/LogsViewer/components/LogsFacetSidebar.js.map +1 -1
- package/build/dist/UI/Components/Modal/ModalFooter.js +1 -1
- package/build/dist/UI/Components/Modal/ModalFooter.js.map +1 -1
- package/build/dist/UI/Components/ModelDetail/CardModelDetail.js +2 -2
- package/build/dist/UI/Components/ModelDetail/CardModelDetail.js.map +1 -1
- package/build/dist/UI/Components/ModelTable/BaseModelTable.js +4 -4
- package/build/dist/UI/Components/ModelTable/BaseModelTable.js.map +1 -1
- package/build/dist/UI/Components/Navbar/NavBar.js +9 -2
- package/build/dist/UI/Components/Navbar/NavBar.js.map +1 -1
- package/build/dist/UI/Components/Navbar/NavBarMenuModal.js +2 -2
- package/build/dist/UI/Components/Navbar/NavBarMenuModal.js.map +1 -1
- package/build/dist/UI/Components/Page/Page.js +1 -1
- package/build/dist/UI/Components/Page/Page.js.map +1 -1
- package/build/dist/UI/Components/Pagination/Pagination.js +3 -3
- package/build/dist/UI/Components/Pagination/Pagination.js.map +1 -1
- package/build/dist/UI/Components/ProgressButtons/ProgressButtonItem.js +1 -1
- package/build/dist/UI/Components/ProgressButtons/ProgressButtonItem.js.map +1 -1
- package/build/dist/UI/Components/SideMenu/SideMenu.js +4 -1
- package/build/dist/UI/Components/SideMenu/SideMenu.js.map +1 -1
- package/build/dist/UI/Components/StatusPage/ResourceGroupNavigator.js +3 -1
- package/build/dist/UI/Components/StatusPage/ResourceGroupNavigator.js.map +1 -1
- package/build/dist/UI/Components/StatusPage/ResourceList.js +6 -6
- package/build/dist/UI/Components/StatusPage/ResourceList.js.map +1 -1
- package/build/dist/UI/Components/TelemetryViewer/components/TelemetryFacetSidebar.js +1 -1
- package/build/dist/UI/Components/TelemetryViewer/components/TelemetryFacetSidebar.js.map +1 -1
- package/build/dist/UI/Components/TelemetryViewer/components/TelemetryFacetValueRow.js +1 -1
- package/build/dist/UI/Components/TelemetryViewer/components/TelemetryFacetValueRow.js.map +1 -1
- package/build/dist/UI/Components/Workflow/ColumnEditor/ModelQueryBuilder.js +1 -1
- package/build/dist/UI/Components/Workflow/ColumnEditor/ModelQueryBuilder.js.map +1 -1
- package/build/dist/UI/Components/Workflow/ComponentsModal.js +2 -2
- package/build/dist/UI/Components/Workflow/ComponentsModal.js.map +1 -1
- package/build/dist/UI/Components/Workflow/StepTraceViewer.js +1 -1
- package/build/dist/UI/Components/Workflow/StepTraceViewer.js.map +1 -1
- package/build/dist/UI/Utils/Navigation.js +66 -33
- package/build/dist/UI/Utils/Navigation.js.map +1 -1
- package/build/dist/UI/Utils/Telemetry/TelemetryEntityNames.js +7 -0
- package/build/dist/UI/Utils/Telemetry/TelemetryEntityNames.js.map +1 -1
- package/build/dist/UI/Utils/TelemetryService.js +3 -2
- package/build/dist/UI/Utils/TelemetryService.js.map +1 -1
- package/build/dist/Utils/Dashboard/KubernetesClusterCpuTileRepair.js +110 -0
- package/build/dist/Utils/Dashboard/KubernetesClusterCpuTileRepair.js.map +1 -0
- package/build/dist/Utils/LabelRuleImportExport.js +2 -0
- package/build/dist/Utils/LabelRuleImportExport.js.map +1 -1
- package/build/dist/Utils/MetricUnitUtil.js +77 -13
- package/build/dist/Utils/MetricUnitUtil.js.map +1 -1
- package/build/dist/Utils/Monitor/MetricValueFormatter.js +58 -13
- package/build/dist/Utils/Monitor/MetricValueFormatter.js.map +1 -1
- package/build/dist/Utils/Monitor/PlatformMetricUnitUtil.js +161 -0
- package/build/dist/Utils/Monitor/PlatformMetricUnitUtil.js.map +1 -0
- package/build/dist/Utils/Monitor/PlatformResourceIdentity.js +323 -0
- package/build/dist/Utils/Monitor/PlatformResourceIdentity.js.map +1 -0
- package/build/dist/Utils/NetworkDiscovery/DiscoveredHostNamingDiagnosis.js +270 -0
- package/build/dist/Utils/NetworkDiscovery/DiscoveredHostNamingDiagnosis.js.map +1 -0
- package/build/dist/Utils/NetworkDiscovery/DiscoveredHostUtil.js +23 -0
- package/build/dist/Utils/NetworkDiscovery/DiscoveredHostUtil.js.map +1 -1
- package/build/dist/Utils/NetworkDiscovery/NetbiosNameUtil.js +61 -0
- package/build/dist/Utils/NetworkDiscovery/NetbiosNameUtil.js.map +1 -1
- package/build/dist/Utils/Telemetry/DatabaseServerEntityKeys.js +178 -0
- package/build/dist/Utils/Telemetry/DatabaseServerEntityKeys.js.map +1 -0
- package/build/dist/Utils/Telemetry/EntityKey.js +133 -0
- package/build/dist/Utils/Telemetry/EntityKey.js.map +1 -1
- package/build/dist/Utils/ValueFormatter.js +15 -0
- package/build/dist/Utils/ValueFormatter.js.map +1 -1
- package/package.json +1 -1
- package/tsconfig.tests.json +7 -5
|
@@ -6,8 +6,10 @@ import CustomCodeMonitoringCriteria from "./Criteria/CustomCodeMonitorCriteria";
|
|
|
6
6
|
import IncomingEmailCriteria from "./Criteria/IncomingEmailCriteria";
|
|
7
7
|
import IncomingRequestCriteria from "./Criteria/IncomingRequestCriteria";
|
|
8
8
|
import IncomingRequestIncidentGrouping from "./IncomingRequestIncidentGrouping";
|
|
9
|
+
import { IOT_DEVICE_ID_ATTRIBUTE_KEY } from "./IoTDeviceAbsenceSeries";
|
|
9
10
|
import PerEntityCriteriaFanOut from "./PerEntityCriteriaFanOut";
|
|
10
11
|
import SSLMonitorCriteria from "./Criteria/SSLMonitorCriteria";
|
|
12
|
+
import CompareCriteria from "./Criteria/CompareCriteria";
|
|
11
13
|
import ServerMonitorCriteria from "./Criteria/ServerMonitorCriteria";
|
|
12
14
|
import SyntheticMonitoringCriteria from "./Criteria/SyntheticMonitor";
|
|
13
15
|
import LogMonitorCriteria from "./Criteria/LogMonitorCriteria";
|
|
@@ -49,6 +51,10 @@ import { getProxmoxMetricByMetricName } from "../../../Types/Monitor/ProxmoxMetr
|
|
|
49
51
|
import { getVMwareMetricByMetricName } from "../../../Types/Monitor/VMwareMetricCatalog";
|
|
50
52
|
import { getCephMetricByMetricName } from "../../../Types/Monitor/CephMetricCatalog";
|
|
51
53
|
import { getDockerSwarmMetricByMetricName } from "../../../Types/Monitor/DockerSwarmMetricCatalog";
|
|
54
|
+
import PlatformMetricUnitUtil from "../../../Utils/Monitor/PlatformMetricUnitUtil";
|
|
55
|
+
import MetricUnitUtil from "../../../Utils/MetricUnitUtil";
|
|
56
|
+
import PlatformResourceIdentity from "../../../Utils/Monitor/PlatformResourceIdentity";
|
|
57
|
+
import MetricFormulaEvaluator from "../../../Utils/Metrics/MetricFormulaEvaluator";
|
|
52
58
|
export default class MonitorCriteriaEvaluator {
|
|
53
59
|
static async processMonitorStep(input) {
|
|
54
60
|
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m;
|
|
@@ -208,6 +214,7 @@ export default class MonitorCriteriaEvaluator {
|
|
|
208
214
|
monitorStep: input.monitorStep,
|
|
209
215
|
monitor: input.monitor,
|
|
210
216
|
criteriaInstance: criteriaInstance,
|
|
217
|
+
perSeriesMatches: perSeriesMatches,
|
|
211
218
|
});
|
|
212
219
|
/*
|
|
213
220
|
* For metric monitors, render the metric identity (name, unit,
|
|
@@ -499,6 +506,9 @@ ${contextBlock}
|
|
|
499
506
|
labels: entry.labels,
|
|
500
507
|
rootCause: rootCauseLines.join("\n"),
|
|
501
508
|
metricContext: (_e = matched[0]) === null || _e === void 0 ? void 0 : _e.context,
|
|
509
|
+
metricContexts: matched.map((r) => {
|
|
510
|
+
return r.context;
|
|
511
|
+
}),
|
|
502
512
|
});
|
|
503
513
|
}
|
|
504
514
|
return matches;
|
|
@@ -927,6 +937,10 @@ ${contextBlock}
|
|
|
927
937
|
if (input.monitor.monitorType === MonitorType.Podman) {
|
|
928
938
|
return MonitorCriteriaEvaluator.buildPodmanRootCauseContext(input);
|
|
929
939
|
}
|
|
940
|
+
// Handle IoT device monitors with fleet / device context
|
|
941
|
+
if (input.monitor.monitorType === MonitorType.IoTDevice) {
|
|
942
|
+
return MonitorCriteriaEvaluator.buildIoTRootCauseContext(input);
|
|
943
|
+
}
|
|
930
944
|
// Handle Proxmox monitors with resource context
|
|
931
945
|
if (input.monitor.monitorType === MonitorType.Proxmox) {
|
|
932
946
|
return MonitorCriteriaEvaluator.buildProxmoxRootCauseContext(input);
|
|
@@ -1026,20 +1040,23 @@ ${contextBlock}
|
|
|
1026
1040
|
}
|
|
1027
1041
|
return sections.join("\n");
|
|
1028
1042
|
}
|
|
1029
|
-
|
|
1043
|
+
/*
|
|
1044
|
+
* The first populated metric context across the instance's filters.
|
|
1045
|
+
* Only metric-value filters populate this at evaluation time, so this
|
|
1046
|
+
* effectively returns the context for the filter that ran.
|
|
1047
|
+
*/
|
|
1048
|
+
static getMetricCriteriaContext(criteriaInstance) {
|
|
1030
1049
|
var _a;
|
|
1031
|
-
|
|
1032
|
-
* Pick the first populated metric context across the instance's filters.
|
|
1033
|
-
* Only metric-value filters populate this at evaluation time, so this
|
|
1034
|
-
* effectively returns the context for the filter that ran.
|
|
1035
|
-
*/
|
|
1036
|
-
const ctx = (((_a = input.criteriaInstance.data) === null || _a === void 0 ? void 0 : _a.filters) || [])
|
|
1050
|
+
return (((_a = criteriaInstance === null || criteriaInstance === void 0 ? void 0 : criteriaInstance.data) === null || _a === void 0 ? void 0 : _a.filters) || [])
|
|
1037
1051
|
.map((f) => {
|
|
1038
1052
|
return f.metricCriteriaContext;
|
|
1039
1053
|
})
|
|
1040
1054
|
.find((c) => {
|
|
1041
1055
|
return Boolean(c);
|
|
1042
1056
|
});
|
|
1057
|
+
}
|
|
1058
|
+
static buildMetricRootCauseContext(input) {
|
|
1059
|
+
const ctx = MonitorCriteriaEvaluator.getMetricCriteriaContext(input.criteriaInstance);
|
|
1043
1060
|
if (!ctx) {
|
|
1044
1061
|
return null;
|
|
1045
1062
|
}
|
|
@@ -1117,11 +1134,16 @@ ${contextBlock}
|
|
|
1117
1134
|
unit: ctx.unit,
|
|
1118
1135
|
unitHeuristicMetricName: unitHeuristicMetricName,
|
|
1119
1136
|
components: ctx.components || [],
|
|
1137
|
+
seriesLabelKeys: [
|
|
1138
|
+
...ctx.groupBy,
|
|
1139
|
+
...Object.keys(ctx.seriesLabels || {}),
|
|
1140
|
+
],
|
|
1120
1141
|
})}`);
|
|
1121
1142
|
}
|
|
1122
1143
|
const deepLink = MonitorCriteriaEvaluator.buildMetricExplorerDeepLink({
|
|
1123
1144
|
monitor: input.monitor,
|
|
1124
1145
|
ctx,
|
|
1146
|
+
monitorStep: input.monitorStep,
|
|
1125
1147
|
});
|
|
1126
1148
|
if (deepLink) {
|
|
1127
1149
|
sections.push(`\n\n[Open metric in dashboard](${deepLink})`);
|
|
@@ -1175,6 +1197,41 @@ ${contextBlock}
|
|
|
1175
1197
|
* the client-side markdown viewer can localize them to the viewer's
|
|
1176
1198
|
* timezone (without losing the canonical instant).
|
|
1177
1199
|
*/
|
|
1200
|
+
/**
|
|
1201
|
+
* The attributes worth printing under a breaching sample.
|
|
1202
|
+
*
|
|
1203
|
+
* A grouped monitor's sample does not carry its group-by values at the
|
|
1204
|
+
* top level: the worker nests the datapoint's whole attribute map under
|
|
1205
|
+
* a single `attributes` key. Printed as-is that became
|
|
1206
|
+
* "`attributes`: `[object Object]`" under every sample — the one line
|
|
1207
|
+
* that should have said which host breached. The series' own label keys
|
|
1208
|
+
* are lifted out of it instead; the rest of the datapoint's attributes
|
|
1209
|
+
* (every resource attribute the exporter stamped) are not what the
|
|
1210
|
+
* reader is looking for here.
|
|
1211
|
+
*/
|
|
1212
|
+
static flattenSampleAttributes(input) {
|
|
1213
|
+
const flattened = {};
|
|
1214
|
+
for (const key of Object.keys(input.attributes)) {
|
|
1215
|
+
const value = input.attributes[key];
|
|
1216
|
+
if (value && typeof value === "object" && !Array.isArray(value)) {
|
|
1217
|
+
for (const nestedKey of Object.keys(value)) {
|
|
1218
|
+
const nestedValue = value[nestedKey];
|
|
1219
|
+
if (input.seriesLabelKeys.has(nestedKey) &&
|
|
1220
|
+
flattened[nestedKey] === undefined &&
|
|
1221
|
+
nestedValue !== undefined &&
|
|
1222
|
+
nestedValue !== null &&
|
|
1223
|
+
typeof nestedValue !== "object") {
|
|
1224
|
+
flattened[nestedKey] = nestedValue;
|
|
1225
|
+
}
|
|
1226
|
+
}
|
|
1227
|
+
continue;
|
|
1228
|
+
}
|
|
1229
|
+
if (flattened[key] === undefined) {
|
|
1230
|
+
flattened[key] = value;
|
|
1231
|
+
}
|
|
1232
|
+
}
|
|
1233
|
+
return flattened;
|
|
1234
|
+
}
|
|
1178
1235
|
static formatBreachingSamplesSection(input) {
|
|
1179
1236
|
const MAX_SAMPLES_SHOWN = 20;
|
|
1180
1237
|
// Sort chronologically and de-duplicate any accidental repeats
|
|
@@ -1186,14 +1243,22 @@ ${contextBlock}
|
|
|
1186
1243
|
* Collect attribute keys that appear on any displayed sample, so every
|
|
1187
1244
|
* item lists the attributes it has in the same order.
|
|
1188
1245
|
*/
|
|
1246
|
+
const seriesLabelKeys = new Set(input.seriesLabelKeys || []);
|
|
1247
|
+
const sampleAttributes = new Map();
|
|
1189
1248
|
const attrKeySet = new Set();
|
|
1190
1249
|
for (const s of displayedSamples) {
|
|
1191
|
-
|
|
1250
|
+
const flattened = MonitorCriteriaEvaluator.flattenSampleAttributes({
|
|
1251
|
+
attributes: s.attributes || {},
|
|
1252
|
+
seriesLabelKeys: seriesLabelKeys,
|
|
1253
|
+
});
|
|
1254
|
+
sampleAttributes.set(s, flattened);
|
|
1255
|
+
for (const k of Object.keys(flattened)) {
|
|
1192
1256
|
attrKeySet.add(k);
|
|
1193
1257
|
}
|
|
1194
1258
|
}
|
|
1195
1259
|
const attrKeys = Array.from(attrKeySet);
|
|
1196
1260
|
const items = displayedSamples.map((s) => {
|
|
1261
|
+
var _a;
|
|
1197
1262
|
const details = [];
|
|
1198
1263
|
/*
|
|
1199
1264
|
* What each variable of a formula resolved to at the breach time —
|
|
@@ -1233,7 +1298,7 @@ ${contextBlock}
|
|
|
1233
1298
|
* RootCauseList.code keeps whatever they contain inside the span.
|
|
1234
1299
|
*/
|
|
1235
1300
|
for (const k of attrKeys) {
|
|
1236
|
-
const v = s
|
|
1301
|
+
const v = (_a = sampleAttributes.get(s)) === null || _a === void 0 ? void 0 : _a[k];
|
|
1237
1302
|
if (v === undefined || v === null) {
|
|
1238
1303
|
continue;
|
|
1239
1304
|
}
|
|
@@ -1290,17 +1355,39 @@ ${contextBlock}
|
|
|
1290
1355
|
* for its own URL round-trip — so this deep link can never drift
|
|
1291
1356
|
* from what the explorer parses.
|
|
1292
1357
|
*/
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1358
|
+
let queryConfigs = [
|
|
1359
|
+
{
|
|
1360
|
+
metricQueryData: {
|
|
1361
|
+
filterData: Object.assign({ metricName: input.ctx.metricName, attributes: MetricExplorerUrl.sanitizeAttributes(input.ctx.filterAttributes) }, (input.ctx.aggregationType
|
|
1362
|
+
? { aggegationType: input.ctx.aggregationType }
|
|
1363
|
+
: {})),
|
|
1364
|
+
},
|
|
1298
1365
|
},
|
|
1299
|
-
|
|
1366
|
+
];
|
|
1367
|
+
let formulaConfigs = [];
|
|
1368
|
+
/*
|
|
1369
|
+
* A formula's metricName is its EXPRESSION, not a metric the explorer
|
|
1370
|
+
* can chart — linking it as one opened an empty chart. Open the
|
|
1371
|
+
* step's own queries and formulas instead, which is what the formula
|
|
1372
|
+
* was computed from. With no step config to rebuild it from, no link
|
|
1373
|
+
* beats a dead one.
|
|
1374
|
+
*/
|
|
1375
|
+
if (input.ctx.isFormula) {
|
|
1376
|
+
const metricViewConfig = MonitorStep.getMetricsViewConfig(input.monitorStep);
|
|
1377
|
+
if (!metricViewConfig ||
|
|
1378
|
+
!(metricViewConfig.formulaConfigs || []).some((formula) => {
|
|
1379
|
+
var _a;
|
|
1380
|
+
return ((_a = formula.metricAliasData) === null || _a === void 0 ? void 0 : _a.metricVariable) === input.ctx.alias;
|
|
1381
|
+
})) {
|
|
1382
|
+
return null;
|
|
1383
|
+
}
|
|
1384
|
+
queryConfigs = metricViewConfig.queryConfigs || [];
|
|
1385
|
+
formulaConfigs = metricViewConfig.formulaConfigs || [];
|
|
1386
|
+
}
|
|
1300
1387
|
const breachWindow = MonitorCriteriaEvaluator.getMetricBreachExplorerWindow(input.ctx);
|
|
1301
1388
|
const urlParams = MetricExplorerUrl.buildQueryParamsFromMetricViewData({
|
|
1302
|
-
queryConfigs:
|
|
1303
|
-
formulaConfigs:
|
|
1389
|
+
queryConfigs: queryConfigs,
|
|
1390
|
+
formulaConfigs: formulaConfigs,
|
|
1304
1391
|
startAndEndDate: new InBetween(breachWindow.startTime, breachWindow.endTime),
|
|
1305
1392
|
});
|
|
1306
1393
|
const params = new URLSearchParams();
|
|
@@ -1425,7 +1512,8 @@ ${contextBlock}
|
|
|
1425
1512
|
return ` _(scope partially carried — not applied: ${dropped.join(", ")})_`;
|
|
1426
1513
|
}
|
|
1427
1514
|
/**
|
|
1428
|
-
* The unit for a value in a per-platform "Affected Resources" list
|
|
1515
|
+
* The unit for a value in a per-platform "Affected Resources" list built
|
|
1516
|
+
* from the worker's raw datapoint scan.
|
|
1429
1517
|
*
|
|
1430
1518
|
* These rows are NOT the same numbers as the criteria's breaching
|
|
1431
1519
|
* samples: the worker collects them with a raw `MetricService.findBy`
|
|
@@ -1435,50 +1523,632 @@ ${contextBlock}
|
|
|
1435
1523
|
* query's legendUnit would therefore attach a confidently wrong unit to
|
|
1436
1524
|
* a correct number.
|
|
1437
1525
|
*
|
|
1438
|
-
* The catalog is the
|
|
1526
|
+
* The catalog is the first source precisely because it also declares
|
|
1439
1527
|
* the native unit. It is the same lookup, on the same metric name, that
|
|
1440
1528
|
* the worker already ran to resolve `metricFriendlyName`, so the unit
|
|
1441
1529
|
* shown here can never disagree with the metric name shown beside it.
|
|
1530
|
+
* The unit the worker recorded on the breakdown — the one the exporter
|
|
1531
|
+
* declared — covers every metric the catalog does not know, which is
|
|
1532
|
+
* how k8s.node.allocatable_memory reads "258 GB" instead of the bare
|
|
1533
|
+
* "257760964608" it used to.
|
|
1442
1534
|
*/
|
|
1443
1535
|
static getPlatformMetricUnit(input) {
|
|
1536
|
+
/*
|
|
1537
|
+
* The vcenter receiver's utilization metrics are already 0–100
|
|
1538
|
+
* percentages (unit "%"), never [0, 1] ratios — the catalog says "%"
|
|
1539
|
+
* and the formatter renders it as-is, so 92.5 reads "92.50%" and
|
|
1540
|
+
* never "9250.00%".
|
|
1541
|
+
*/
|
|
1542
|
+
return (PlatformMetricUnitUtil.getCatalogUnit({
|
|
1543
|
+
platform: input.platform,
|
|
1544
|
+
metricName: input.metricName,
|
|
1545
|
+
}) ||
|
|
1546
|
+
input.metricUnit ||
|
|
1547
|
+
undefined);
|
|
1548
|
+
}
|
|
1549
|
+
/**
|
|
1550
|
+
* Render the value of one resource from the worker's raw scan, in the
|
|
1551
|
+
* unit getPlatformMetricUnit resolves. Unemphasised: the list bolds it
|
|
1552
|
+
* (it is the one number on the line a reader scans for), a sentence
|
|
1553
|
+
* may not.
|
|
1554
|
+
*/
|
|
1555
|
+
static formatPlatformMetricValue(input) {
|
|
1556
|
+
return MetricValueFormatter.format({
|
|
1557
|
+
value: input.value,
|
|
1558
|
+
unit: MonitorCriteriaEvaluator.getPlatformMetricUnit({
|
|
1559
|
+
platform: input.platform,
|
|
1560
|
+
metricName: input.metricName,
|
|
1561
|
+
metricUnit: input.metricUnit,
|
|
1562
|
+
}),
|
|
1563
|
+
metricName: input.metricName,
|
|
1564
|
+
});
|
|
1565
|
+
}
|
|
1566
|
+
/**
|
|
1567
|
+
* The catalog's human name for a platform metric, or undefined when the
|
|
1568
|
+
* catalog does not know it.
|
|
1569
|
+
*/
|
|
1570
|
+
static getPlatformMetricFriendlyName(input) {
|
|
1444
1571
|
var _a, _b, _c, _d, _e;
|
|
1445
1572
|
switch (input.platform) {
|
|
1446
1573
|
case "kubernetes":
|
|
1447
|
-
return (_a = getKubernetesMetricByMetricName(input.metricName)) === null || _a === void 0 ? void 0 : _a.
|
|
1574
|
+
return (_a = getKubernetesMetricByMetricName(input.metricName)) === null || _a === void 0 ? void 0 : _a.friendlyName;
|
|
1448
1575
|
case "proxmox":
|
|
1449
|
-
return (_b = getProxmoxMetricByMetricName(input.metricName)) === null || _b === void 0 ? void 0 : _b.
|
|
1576
|
+
return (_b = getProxmoxMetricByMetricName(input.metricName)) === null || _b === void 0 ? void 0 : _b.friendlyName;
|
|
1450
1577
|
case "vmware":
|
|
1451
|
-
|
|
1452
|
-
* The vcenter receiver's utilization metrics are already 0–100
|
|
1453
|
-
* percentages (unit "%"), never [0, 1] ratios — the catalog
|
|
1454
|
-
* says "%" and the formatter renders it as-is, so 92.5 reads
|
|
1455
|
-
* "92.50%" and never "9250.00%".
|
|
1456
|
-
*/
|
|
1457
|
-
return (_c = getVMwareMetricByMetricName(input.metricName)) === null || _c === void 0 ? void 0 : _c.unit;
|
|
1578
|
+
return (_c = getVMwareMetricByMetricName(input.metricName)) === null || _c === void 0 ? void 0 : _c.friendlyName;
|
|
1458
1579
|
case "dockerSwarm":
|
|
1459
|
-
return (_d = getDockerSwarmMetricByMetricName(input.metricName)) === null || _d === void 0 ? void 0 : _d.
|
|
1580
|
+
return (_d = getDockerSwarmMetricByMetricName(input.metricName)) === null || _d === void 0 ? void 0 : _d.friendlyName;
|
|
1460
1581
|
case "ceph":
|
|
1461
|
-
return (_e = getCephMetricByMetricName(input.metricName)) === null || _e === void 0 ? void 0 : _e.
|
|
1582
|
+
return (_e = getCephMetricByMetricName(input.metricName)) === null || _e === void 0 ? void 0 : _e.friendlyName;
|
|
1462
1583
|
default:
|
|
1463
1584
|
return undefined;
|
|
1464
1585
|
}
|
|
1465
1586
|
}
|
|
1466
1587
|
/**
|
|
1467
|
-
*
|
|
1468
|
-
*
|
|
1588
|
+
* "Node Memory Usage (`k8s.node.memory.usage`)", or just the code-quoted
|
|
1589
|
+
* name when there is no friendlier one. The old line always printed
|
|
1590
|
+
* both, which is how the email came to read
|
|
1591
|
+
* "k8s.node.allocatable_memory (`k8s.node.allocatable_memory`)".
|
|
1592
|
+
*/
|
|
1593
|
+
static describePlatformMetricName(input) {
|
|
1594
|
+
const friendlyName = (input.friendlyName || "").trim();
|
|
1595
|
+
if (!friendlyName || friendlyName === input.metricName) {
|
|
1596
|
+
return `\`${input.metricName}\``;
|
|
1597
|
+
}
|
|
1598
|
+
return `${friendlyName} (\`${input.metricName}\`)`;
|
|
1599
|
+
}
|
|
1600
|
+
/**
|
|
1601
|
+
* What the matched criteria actually measured: the query or formula its
|
|
1602
|
+
* metric-value filter points at, resolved the same way
|
|
1603
|
+
* MetricMonitorCriteria resolves it (alias match, falling back to the
|
|
1604
|
+
* first query when the alias names nothing).
|
|
1469
1605
|
*
|
|
1470
|
-
*
|
|
1471
|
-
*
|
|
1606
|
+
* Returns null when the criteria has no metric-value filter — the
|
|
1607
|
+
* platform context then falls back to describing the breakdown, as it
|
|
1608
|
+
* always has.
|
|
1472
1609
|
*/
|
|
1473
|
-
static
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
1610
|
+
static resolveCriteriaMetricTarget(input) {
|
|
1611
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k;
|
|
1612
|
+
/*
|
|
1613
|
+
* The step's own config, exactly as MetricMonitorCriteria reads it,
|
|
1614
|
+
* so the target named here is the one the criteria was evaluated on.
|
|
1615
|
+
*/
|
|
1616
|
+
const stepConfig = MonitorStep.getMetricsViewConfig(input.monitorStep);
|
|
1617
|
+
const metricViewConfig = stepConfig && ((_a = stepConfig.queryConfigs) === null || _a === void 0 ? void 0 : _a.length) > 0
|
|
1618
|
+
? stepConfig
|
|
1619
|
+
: input.metricResponse.metricViewConfig || stepConfig;
|
|
1620
|
+
const metricFilters = (((_c = (_b = input.criteriaInstance) === null || _b === void 0 ? void 0 : _b.data) === null || _c === void 0 ? void 0 : _c.filters) || []).filter((f) => {
|
|
1621
|
+
return f.checkOn === CheckOn.MetricValue;
|
|
1622
|
+
});
|
|
1623
|
+
if (metricFilters.length === 0) {
|
|
1624
|
+
return null;
|
|
1625
|
+
}
|
|
1626
|
+
/*
|
|
1627
|
+
* The filter that actually fired, when the criteria has several. An
|
|
1628
|
+
* "Any" criteria (ceph-pg-damaged: PG_DAMAGED > 0 OR OSD_SCRUB_ERRORS
|
|
1629
|
+
* > 0) is described — and its list taken from — whichever of them
|
|
1630
|
+
* breached. Following the first filter instead found no scan for an
|
|
1631
|
+
* inactive PG_DAMAGED check and dropped the list the scrub errors had.
|
|
1632
|
+
* The evaluation leaves each filter's context on it; one with
|
|
1633
|
+
* breaching samples is one that fired.
|
|
1634
|
+
*/
|
|
1635
|
+
const firedFilter = metricFilters.find((f) => {
|
|
1636
|
+
const context = f.metricCriteriaContext;
|
|
1637
|
+
return Boolean(((context === null || context === void 0 ? void 0 : context.breachingSamples) && context.breachingSamples.length > 0) ||
|
|
1638
|
+
(context === null || context === void 0 ? void 0 : context.breachingSample));
|
|
1639
|
+
});
|
|
1640
|
+
const filter = firedFilter ||
|
|
1641
|
+
metricFilters.find((f) => {
|
|
1642
|
+
var _a;
|
|
1643
|
+
return Boolean((_a = f.metricMonitorOptions) === null || _a === void 0 ? void 0 : _a.metricAlias);
|
|
1644
|
+
}) ||
|
|
1645
|
+
metricFilters[0];
|
|
1646
|
+
const thresholdUnit = ((_d = filter.metricMonitorOptions) === null || _d === void 0 ? void 0 : _d.thresholdUnit) || undefined;
|
|
1647
|
+
const alias = ((_e = filter.metricMonitorOptions) === null || _e === void 0 ? void 0 : _e.metricAlias) || "";
|
|
1648
|
+
const queryConfigs = (metricViewConfig === null || metricViewConfig === void 0 ? void 0 : metricViewConfig.queryConfigs) || [];
|
|
1649
|
+
const formulaConfigs = (metricViewConfig === null || metricViewConfig === void 0 ? void 0 : metricViewConfig.formulaConfigs) || [];
|
|
1650
|
+
const aliasOf = (config) => {
|
|
1651
|
+
var _a;
|
|
1652
|
+
return ((_a = config.metricAliasData) === null || _a === void 0 ? void 0 : _a.metricVariable) || "";
|
|
1653
|
+
};
|
|
1654
|
+
const query = alias
|
|
1655
|
+
? queryConfigs.find((q) => {
|
|
1656
|
+
return aliasOf(q) === alias;
|
|
1657
|
+
})
|
|
1658
|
+
: undefined;
|
|
1659
|
+
const formula = !query && alias
|
|
1660
|
+
? formulaConfigs.find((f) => {
|
|
1661
|
+
return aliasOf(f) === alias;
|
|
1662
|
+
})
|
|
1663
|
+
: undefined;
|
|
1664
|
+
if (formula) {
|
|
1665
|
+
const expression = ((_f = formula.metricFormulaData) === null || _f === void 0 ? void 0 : _f.metricFormula) || "";
|
|
1666
|
+
const components = MetricFormulaEvaluator.getReferencedVariables(expression).map((variable) => {
|
|
1667
|
+
var _a, _b;
|
|
1668
|
+
const componentQuery = queryConfigs.find((q) => {
|
|
1669
|
+
return aliasOf(q).toLowerCase() === variable.toLowerCase();
|
|
1670
|
+
});
|
|
1671
|
+
return {
|
|
1672
|
+
alias: componentQuery ? aliasOf(componentQuery) : variable,
|
|
1673
|
+
metricName: ((_b = (_a = componentQuery === null || componentQuery === void 0 ? void 0 : componentQuery.metricQueryData) === null || _a === void 0 ? void 0 : _a.filterData) === null || _b === void 0 ? void 0 : _b.metricName) || undefined,
|
|
1674
|
+
};
|
|
1675
|
+
});
|
|
1676
|
+
return {
|
|
1677
|
+
alias: alias,
|
|
1678
|
+
isFormula: true,
|
|
1679
|
+
comparisonUnit: thresholdUnit || ((_g = formula.metricAliasData) === null || _g === void 0 ? void 0 : _g.legendUnit) || undefined,
|
|
1680
|
+
metricName: undefined,
|
|
1681
|
+
displayName: MetricMonitorCriteria.getAliasDisplayName({
|
|
1682
|
+
aliasData: formula.metricAliasData,
|
|
1683
|
+
metricAlias: alias,
|
|
1684
|
+
}),
|
|
1685
|
+
formulaExpression: expression || undefined,
|
|
1686
|
+
components: components,
|
|
1687
|
+
};
|
|
1688
|
+
}
|
|
1689
|
+
const matchedQuery = query || queryConfigs[0];
|
|
1690
|
+
if (!matchedQuery) {
|
|
1691
|
+
return null;
|
|
1692
|
+
}
|
|
1693
|
+
return {
|
|
1694
|
+
alias: aliasOf(matchedQuery) || alias,
|
|
1695
|
+
isFormula: false,
|
|
1696
|
+
comparisonUnit: thresholdUnit || ((_h = matchedQuery.metricAliasData) === null || _h === void 0 ? void 0 : _h.legendUnit) || undefined,
|
|
1697
|
+
metricName: ((_k = (_j = matchedQuery.metricQueryData) === null || _j === void 0 ? void 0 : _j.filterData) === null || _k === void 0 ? void 0 : _k.metricName) || undefined,
|
|
1698
|
+
displayName: MetricMonitorCriteria.getAliasDisplayName({
|
|
1699
|
+
aliasData: matchedQuery.metricAliasData,
|
|
1700
|
+
metricAlias: aliasOf(matchedQuery) || alias,
|
|
1479
1701
|
}),
|
|
1480
|
-
|
|
1481
|
-
|
|
1702
|
+
formulaExpression: undefined,
|
|
1703
|
+
components: [],
|
|
1704
|
+
};
|
|
1705
|
+
}
|
|
1706
|
+
/**
|
|
1707
|
+
* The metric the platform's root-cause analysis should reason about. For
|
|
1708
|
+
* a plain query that is the query's metric. A formula has no metric name
|
|
1709
|
+
* of its own, so it is analysed as its first query component — the
|
|
1710
|
+
* numerator of every ratio template (k8s.node.memory.usage for
|
|
1711
|
+
* "used ÷ allocatable"), which is what the analysis branches key on.
|
|
1712
|
+
*/
|
|
1713
|
+
static getAnalysisMetricName(target) {
|
|
1714
|
+
var _a;
|
|
1715
|
+
if (!target) {
|
|
1716
|
+
return undefined;
|
|
1717
|
+
}
|
|
1718
|
+
if (!target.isFormula) {
|
|
1719
|
+
return target.metricName;
|
|
1720
|
+
}
|
|
1721
|
+
return (_a = target.components.find((component) => {
|
|
1722
|
+
return Boolean(component.metricName);
|
|
1723
|
+
})) === null || _a === void 0 ? void 0 : _a.metricName;
|
|
1724
|
+
}
|
|
1725
|
+
/**
|
|
1726
|
+
* The "- Metric:" lines of a platform's details block.
|
|
1727
|
+
*
|
|
1728
|
+
* They name what the criteria compared. A formula is named by its
|
|
1729
|
+
* legend and spelled out with the metric behind each variable, because
|
|
1730
|
+
* "Node Memory Utilization (%)" is what the threshold was about and the
|
|
1731
|
+
* two metrics are what an engineer greps for. With no criteria to go on,
|
|
1732
|
+
* the breakdown's own metric is named, as before.
|
|
1733
|
+
*/
|
|
1734
|
+
static describeCriteriaMetric(input) {
|
|
1735
|
+
const target = input.target;
|
|
1736
|
+
const describeMetric = (metricName) => {
|
|
1737
|
+
var _a;
|
|
1738
|
+
const breakdownFriendlyName = ((_a = input.breakdown) === null || _a === void 0 ? void 0 : _a.metricName) === metricName
|
|
1739
|
+
? input.breakdown.metricFriendlyName
|
|
1740
|
+
: undefined;
|
|
1741
|
+
return MonitorCriteriaEvaluator.describePlatformMetricName({
|
|
1742
|
+
metricName: metricName,
|
|
1743
|
+
friendlyName: breakdownFriendlyName ||
|
|
1744
|
+
MonitorCriteriaEvaluator.getPlatformMetricFriendlyName({
|
|
1745
|
+
platform: input.platform,
|
|
1746
|
+
metricName: metricName,
|
|
1747
|
+
}),
|
|
1748
|
+
});
|
|
1749
|
+
};
|
|
1750
|
+
if (target === null || target === void 0 ? void 0 : target.isFormula) {
|
|
1751
|
+
const lines = [
|
|
1752
|
+
`- Metric: ${target.displayName || `\`${target.alias}\``}`,
|
|
1753
|
+
];
|
|
1754
|
+
if (target.formulaExpression) {
|
|
1755
|
+
lines.push(`- Formula: \`${target.formulaExpression}\``);
|
|
1756
|
+
}
|
|
1757
|
+
for (const component of target.components) {
|
|
1758
|
+
if (component.metricName) {
|
|
1759
|
+
lines.push(` - \`${component.alias}\` = ${describeMetric(component.metricName)}`);
|
|
1760
|
+
}
|
|
1761
|
+
}
|
|
1762
|
+
return lines;
|
|
1763
|
+
}
|
|
1764
|
+
if (target === null || target === void 0 ? void 0 : target.metricName) {
|
|
1765
|
+
return [`- Metric: ${describeMetric(target.metricName)}`];
|
|
1766
|
+
}
|
|
1767
|
+
if (input.breakdown) {
|
|
1768
|
+
return [
|
|
1769
|
+
`- Metric: ${MonitorCriteriaEvaluator.describePlatformMetricName({
|
|
1770
|
+
metricName: input.breakdown.metricName,
|
|
1771
|
+
friendlyName: input.breakdown.metricFriendlyName,
|
|
1772
|
+
})}`,
|
|
1773
|
+
];
|
|
1774
|
+
}
|
|
1775
|
+
if (input.fallbackMetricName) {
|
|
1776
|
+
return [`- Metric: \`${input.fallbackMetricName}\``];
|
|
1777
|
+
}
|
|
1778
|
+
return [];
|
|
1779
|
+
}
|
|
1780
|
+
/**
|
|
1781
|
+
* Pick the raw-scan breakdown that measured what the criteria compared.
|
|
1782
|
+
*
|
|
1783
|
+
* The worker returns one breakdown per query, tagged with the query's
|
|
1784
|
+
* alias. Only the one scanned for the criteria's own query may be shown:
|
|
1785
|
+
* a sibling query's scan is a different quantity (allocatable bytes
|
|
1786
|
+
* under a utilization threshold), and a formula has no raw scan at all
|
|
1787
|
+
* — its per-resource values only exist per series.
|
|
1788
|
+
*
|
|
1789
|
+
* A breakdown built before the tag existed is trusted the way it always
|
|
1790
|
+
* was, unless the criteria targets a formula.
|
|
1791
|
+
*/
|
|
1792
|
+
static selectPlatformBreakdown(input) {
|
|
1793
|
+
const candidates = input.breakdowns && input.breakdowns.length > 0
|
|
1794
|
+
? input.breakdowns
|
|
1795
|
+
: input.legacyBreakdown
|
|
1796
|
+
? [input.legacyBreakdown]
|
|
1797
|
+
: [];
|
|
1798
|
+
if (candidates.length === 0) {
|
|
1799
|
+
return undefined;
|
|
1800
|
+
}
|
|
1801
|
+
const target = input.target;
|
|
1802
|
+
if (!target) {
|
|
1803
|
+
return candidates.length === 1 ? candidates[0] : undefined;
|
|
1804
|
+
}
|
|
1805
|
+
if (target.isFormula) {
|
|
1806
|
+
return undefined;
|
|
1807
|
+
}
|
|
1808
|
+
const byAlias = candidates.find((b) => {
|
|
1809
|
+
return (Boolean(b.metricAlias) &&
|
|
1810
|
+
b.metricAlias.toLowerCase() === target.alias.toLowerCase());
|
|
1811
|
+
});
|
|
1812
|
+
if (byAlias) {
|
|
1813
|
+
return byAlias;
|
|
1814
|
+
}
|
|
1815
|
+
return candidates.find((b) => {
|
|
1816
|
+
return !b.metricAlias;
|
|
1817
|
+
});
|
|
1818
|
+
}
|
|
1819
|
+
/**
|
|
1820
|
+
* The "Affected Resources" rows of a GROUPED platform monitor: one per
|
|
1821
|
+
* series that satisfied the matched criteria.
|
|
1822
|
+
*
|
|
1823
|
+
* This is the list the criteria actually produced. Each row is valued
|
|
1824
|
+
* with its series' worst breaching sample, in the same display unit —
|
|
1825
|
+
* and formatted by the same formatter — as the "Filter Conditions Met"
|
|
1826
|
+
* sentence above it, so the node the sentence says "ranged from 86.26%
|
|
1827
|
+
* to 88.82%" is listed at 88.82%, not at its 257760964608 bytes of
|
|
1828
|
+
* allocatable memory. Series that did not breach are not listed at all.
|
|
1829
|
+
*
|
|
1830
|
+
* The resource is named from the series' group-by labels, the same
|
|
1831
|
+
* attribute keys the worker's raw scan reads, then given whatever
|
|
1832
|
+
* context those labels imply but do not carry (a pod's node and
|
|
1833
|
+
* workload) from one of the series' own datapoints.
|
|
1834
|
+
*/
|
|
1835
|
+
static buildSeriesAffectedRows(input) {
|
|
1836
|
+
const targetAlias = (input.targetAlias || "").toLowerCase();
|
|
1837
|
+
const rows = input.perSeriesMatches.map((match) => {
|
|
1838
|
+
var _a;
|
|
1839
|
+
/*
|
|
1840
|
+
* Value the row with the filter the list is about. Under an "Any"
|
|
1841
|
+
* criteria a series may have matched on another filter only; its
|
|
1842
|
+
* value is then a different metric in a different unit, so it is
|
|
1843
|
+
* shown with that metric named and never ranked against the rest.
|
|
1844
|
+
*/
|
|
1845
|
+
const matchedContexts = match.metricContexts && match.metricContexts.length > 0
|
|
1846
|
+
? match.metricContexts
|
|
1847
|
+
: match.metricContext
|
|
1848
|
+
? [match.metricContext]
|
|
1849
|
+
: [];
|
|
1850
|
+
const targetContext = targetAlias
|
|
1851
|
+
? matchedContexts.find((c) => {
|
|
1852
|
+
return (c.alias || "").toLowerCase() === targetAlias;
|
|
1853
|
+
})
|
|
1854
|
+
: matchedContexts[0];
|
|
1855
|
+
const context = targetContext || matchedContexts[0];
|
|
1856
|
+
const valueNote = !targetContext && context
|
|
1857
|
+
? context.displayName || `\`${context.alias}\``
|
|
1858
|
+
: undefined;
|
|
1859
|
+
const seriesIdentity = input.toIdentity(PlatformResourceIdentity.withBothAttributeSpellings(match.labels || {}));
|
|
1860
|
+
const sample = ((_a = context === null || context === void 0 ? void 0 : context.breachingSamples) === null || _a === void 0 ? void 0 : _a[0]) || (context === null || context === void 0 ? void 0 : context.breachingSample);
|
|
1861
|
+
const sampleAttributes = MonitorCriteriaEvaluator.getSampleRawAttributes(sample);
|
|
1862
|
+
/*
|
|
1863
|
+
* The breaching sample's own datapoint first; then a datapoint of
|
|
1864
|
+
* each of the series' queries, because a FORMULA's sample carries
|
|
1865
|
+
* only the group-by labels — a Proxmox ratio over `id` would
|
|
1866
|
+
* otherwise never learn whether the id is a node or a guest.
|
|
1867
|
+
* with<Platform>Context only ever borrows what the series' labels
|
|
1868
|
+
* guarantee is shared, so a row from any of them is safe.
|
|
1869
|
+
*/
|
|
1870
|
+
const contexts = [
|
|
1871
|
+
...(sampleAttributes ? [sampleAttributes] : []),
|
|
1872
|
+
...input.seriesContextAttributes(match.fingerprint),
|
|
1873
|
+
];
|
|
1874
|
+
const identity = contexts.reduce((current, attributes) => {
|
|
1875
|
+
return input.withContext(current, input.toIdentity(PlatformResourceIdentity.withBothAttributeSpellings(attributes)));
|
|
1876
|
+
}, seriesIdentity);
|
|
1877
|
+
const value = MonitorCriteriaEvaluator.getWorstValue({
|
|
1878
|
+
context: context,
|
|
1879
|
+
worstIsLowest: input.worstIsLowest,
|
|
1880
|
+
});
|
|
1881
|
+
const seriesLabels = !input.namesObject(identity)
|
|
1882
|
+
? MonitorCriteriaEvaluator.getNonEmptyLabels(match.labels)
|
|
1883
|
+
: undefined;
|
|
1884
|
+
return Object.assign(Object.assign(Object.assign({ identity: identity, value: value }, (valueNote ? { valueNote: valueNote } : {})), (seriesLabels ? { seriesLabels: seriesLabels } : {})), { formattedValue: value === null
|
|
1885
|
+
? "no data"
|
|
1886
|
+
: MetricValueFormatter.format({
|
|
1887
|
+
value: value,
|
|
1888
|
+
unit: context === null || context === void 0 ? void 0 : context.unit,
|
|
1889
|
+
metricName: MonitorCriteriaEvaluator.metricNameForUnitHeuristics({
|
|
1890
|
+
metricName: context === null || context === void 0 ? void 0 : context.metricName,
|
|
1891
|
+
isFormula: context === null || context === void 0 ? void 0 : context.isFormula,
|
|
1892
|
+
}),
|
|
1893
|
+
}) });
|
|
1894
|
+
});
|
|
1895
|
+
return MonitorCriteriaEvaluator.sortAffectedRows({
|
|
1896
|
+
rows: rows,
|
|
1897
|
+
worstIsLowest: input.worstIsLowest,
|
|
1898
|
+
});
|
|
1899
|
+
}
|
|
1900
|
+
/**
|
|
1901
|
+
* The "Affected Resources" rows of an UNGROUPED platform monitor, from
|
|
1902
|
+
* the worker's raw datapoint scan of the criteria's own query: every
|
|
1903
|
+
* resource the matched criteria's direction says breached, worst first.
|
|
1904
|
+
*/
|
|
1905
|
+
static buildScanAffectedRows(input) {
|
|
1906
|
+
/*
|
|
1907
|
+
* The scan's values are in the metric's own unit, but the criteria
|
|
1908
|
+
* compared its threshold in the filter's threshold unit (or the
|
|
1909
|
+
* query's legendUnit). Judge each row in that unit — a "< 1 min"
|
|
1910
|
+
* uptime criteria must not test 30 seconds against 1 — and show it in
|
|
1911
|
+
* its own.
|
|
1912
|
+
*/
|
|
1913
|
+
const valueUnit = PlatformMetricUnitUtil.getMetricUnit({
|
|
1914
|
+
platform: input.platform,
|
|
1915
|
+
metricName: input.breakdown.metricName,
|
|
1916
|
+
declaredUnit: input.breakdown.metricUnit,
|
|
1917
|
+
});
|
|
1918
|
+
const toComparisonUnit = (value) => {
|
|
1919
|
+
if (!valueUnit ||
|
|
1920
|
+
!input.comparisonUnit ||
|
|
1921
|
+
valueUnit === input.comparisonUnit) {
|
|
1922
|
+
return value;
|
|
1923
|
+
}
|
|
1924
|
+
return MetricUnitUtil.convertToMetricUnit({
|
|
1925
|
+
value: value,
|
|
1926
|
+
fromUnit: valueUnit,
|
|
1927
|
+
metricUnit: input.comparisonUnit,
|
|
1928
|
+
});
|
|
1929
|
+
};
|
|
1930
|
+
const collect = (matches) => {
|
|
1931
|
+
return MonitorCriteriaEvaluator.collectScanRows({
|
|
1932
|
+
platform: input.platform,
|
|
1933
|
+
breakdown: input.breakdown,
|
|
1934
|
+
breach: input.breach,
|
|
1935
|
+
matches: matches,
|
|
1936
|
+
toComparisonUnit: toComparisonUnit,
|
|
1937
|
+
});
|
|
1938
|
+
};
|
|
1939
|
+
let rows = collect(input.breach.matches);
|
|
1940
|
+
if (rows.length === 0 && input.breach.fallbackMatches) {
|
|
1941
|
+
rows = collect(input.breach.fallbackMatches);
|
|
1942
|
+
}
|
|
1943
|
+
return MonitorCriteriaEvaluator.sortAffectedRows({
|
|
1944
|
+
rows: rows,
|
|
1945
|
+
worstIsLowest: input.breach.worstIsLowest,
|
|
1946
|
+
});
|
|
1947
|
+
}
|
|
1948
|
+
/*
|
|
1949
|
+
* One pass of buildScanAffectedRows: the resources `matches` accepts,
|
|
1950
|
+
* each judged in the comparison unit and shown in its own.
|
|
1951
|
+
*/
|
|
1952
|
+
static collectScanRows(input) {
|
|
1953
|
+
var _a;
|
|
1954
|
+
const toComparisonUnit = input.toComparisonUnit;
|
|
1955
|
+
const rows = [];
|
|
1956
|
+
for (const resource of input.breakdown.affectedResources) {
|
|
1957
|
+
const highest = resource.metricValue;
|
|
1958
|
+
const lowest = (_a = resource.lowestMetricValue) !== null && _a !== void 0 ? _a : resource.metricValue;
|
|
1959
|
+
/*
|
|
1960
|
+
* A fall criteria breached on the resource's lowest sample in the
|
|
1961
|
+
* window, not its highest.
|
|
1962
|
+
*/
|
|
1963
|
+
const end = input.breach.pickEnd
|
|
1964
|
+
? input.breach.pickEnd({
|
|
1965
|
+
highest: toComparisonUnit(highest),
|
|
1966
|
+
lowest: toComparisonUnit(lowest),
|
|
1967
|
+
})
|
|
1968
|
+
: input.breach.worstIsLowest
|
|
1969
|
+
? "lowest"
|
|
1970
|
+
: "highest";
|
|
1971
|
+
const value = end === "lowest" ? lowest : highest;
|
|
1972
|
+
if (!input.matches(toComparisonUnit(value))) {
|
|
1973
|
+
continue;
|
|
1974
|
+
}
|
|
1975
|
+
rows.push({
|
|
1976
|
+
identity: resource,
|
|
1977
|
+
value: value,
|
|
1978
|
+
formattedValue: MonitorCriteriaEvaluator.formatPlatformMetricValue({
|
|
1979
|
+
platform: input.platform,
|
|
1980
|
+
metricName: input.breakdown.metricName,
|
|
1981
|
+
metricUnit: input.breakdown.metricUnit,
|
|
1982
|
+
value: value,
|
|
1983
|
+
}),
|
|
1984
|
+
});
|
|
1985
|
+
}
|
|
1986
|
+
return rows;
|
|
1987
|
+
}
|
|
1988
|
+
/*
|
|
1989
|
+
* Worst first. Rows valued by another filter (valueNote) follow, in the
|
|
1990
|
+
* order they came — their numbers are in another unit and cannot be
|
|
1991
|
+
* ranked against these — and a series with no value (a no-data trigger)
|
|
1992
|
+
* comes last.
|
|
1993
|
+
*/
|
|
1994
|
+
static sortAffectedRows(input) {
|
|
1995
|
+
const group = (row) => {
|
|
1996
|
+
if (row.value === null) {
|
|
1997
|
+
return 2;
|
|
1998
|
+
}
|
|
1999
|
+
return row.valueNote ? 1 : 0;
|
|
2000
|
+
};
|
|
2001
|
+
return [...input.rows].sort((a, b) => {
|
|
2002
|
+
if (group(a) !== group(b)) {
|
|
2003
|
+
return group(a) - group(b);
|
|
2004
|
+
}
|
|
2005
|
+
if (group(a) !== 0 || a.value === null || b.value === null) {
|
|
2006
|
+
return 0;
|
|
2007
|
+
}
|
|
2008
|
+
return input.worstIsLowest ? a.value - b.value : b.value - a.value;
|
|
2009
|
+
});
|
|
2010
|
+
}
|
|
2011
|
+
/*
|
|
2012
|
+
* The value cell of a platform list entry: bold, and — for a row valued
|
|
2013
|
+
* by another filter than the list's — followed by that filter's metric.
|
|
2014
|
+
*/
|
|
2015
|
+
static renderAffectedRowValue(row) {
|
|
2016
|
+
return row.valueNote
|
|
2017
|
+
? `**${row.formattedValue}** (${row.valueNote})`
|
|
2018
|
+
: `**${row.formattedValue}**`;
|
|
2019
|
+
}
|
|
2020
|
+
static getNonEmptyLabels(labels) {
|
|
2021
|
+
const result = {};
|
|
2022
|
+
for (const key of Object.keys(labels || {})) {
|
|
2023
|
+
const value = (labels || {})[key];
|
|
2024
|
+
if (value !== undefined && value !== null && value !== "") {
|
|
2025
|
+
result[key] = value;
|
|
2026
|
+
}
|
|
2027
|
+
}
|
|
2028
|
+
return Object.keys(result).length > 0 ? result : undefined;
|
|
2029
|
+
}
|
|
2030
|
+
/*
|
|
2031
|
+
* A list entry for a series whose labels name no platform object: titled
|
|
2032
|
+
* "Series" and named by its labels (their stored `resource.` prefix
|
|
2033
|
+
* dropped), so rows stay distinguishable.
|
|
2034
|
+
*/
|
|
2035
|
+
static getSeriesLabelEntry(input) {
|
|
2036
|
+
const name = Object.keys(input.labels)
|
|
2037
|
+
.map((key) => {
|
|
2038
|
+
const displayKey = key.startsWith("resource.")
|
|
2039
|
+
? key.substring("resource.".length)
|
|
2040
|
+
: key;
|
|
2041
|
+
return AffectedResourceList.code(`${displayKey}=${String(input.labels[key])}`);
|
|
2042
|
+
})
|
|
2043
|
+
.join(", ");
|
|
2044
|
+
return {
|
|
2045
|
+
kind: "Series",
|
|
2046
|
+
name: name,
|
|
2047
|
+
value: input.value,
|
|
2048
|
+
details: [],
|
|
2049
|
+
};
|
|
2050
|
+
}
|
|
2051
|
+
/**
|
|
2052
|
+
* A series' worst value in the display unit: its worst breaching sample,
|
|
2053
|
+
* or — when the criteria compared an aggregate no single sample crossed
|
|
2054
|
+
* (a Sum) — its worst sample in the window. Null for a series that
|
|
2055
|
+
* matched with no samples at all (the no-data policy).
|
|
2056
|
+
*/
|
|
2057
|
+
static getWorstValue(input) {
|
|
2058
|
+
var _a, _b, _c;
|
|
2059
|
+
const breachingValues = (((_a = input.context) === null || _a === void 0 ? void 0 : _a.breachingSamples) ||
|
|
2060
|
+
(((_b = input.context) === null || _b === void 0 ? void 0 : _b.breachingSample) ? [input.context.breachingSample] : []))
|
|
2061
|
+
.map((sample) => {
|
|
2062
|
+
return sample.value;
|
|
2063
|
+
})
|
|
2064
|
+
.filter((value) => {
|
|
2065
|
+
return typeof value === "number" && Number.isFinite(value);
|
|
2066
|
+
});
|
|
2067
|
+
if (breachingValues.length > 0) {
|
|
2068
|
+
return input.worstIsLowest
|
|
2069
|
+
? Math.min(...breachingValues)
|
|
2070
|
+
: Math.max(...breachingValues);
|
|
2071
|
+
}
|
|
2072
|
+
const range = (_c = input.context) === null || _c === void 0 ? void 0 : _c.sampleValueRange;
|
|
2073
|
+
if (range) {
|
|
2074
|
+
return input.worstIsLowest ? range.min : range.max;
|
|
2075
|
+
}
|
|
2076
|
+
return null;
|
|
2077
|
+
}
|
|
2078
|
+
/**
|
|
2079
|
+
* One datapoint's attributes from each QUERY slot of a series (the
|
|
2080
|
+
* formula slots after them carry only group-by labels). Per-series query
|
|
2081
|
+
* rows keep their datapoint's full attribute map under `attributes`.
|
|
2082
|
+
*/
|
|
2083
|
+
static getSeriesQueryRowAttributes(input) {
|
|
2084
|
+
var _a, _b;
|
|
2085
|
+
const series = (input.seriesBreakdown || []).find((s) => {
|
|
2086
|
+
return s.fingerprint === input.fingerprint;
|
|
2087
|
+
});
|
|
2088
|
+
if (!series) {
|
|
2089
|
+
return [];
|
|
2090
|
+
}
|
|
2091
|
+
const result = [];
|
|
2092
|
+
for (let i = 0; i < input.queryCount; i++) {
|
|
2093
|
+
const row = (_b = (_a = series.aggregatedResults[i]) === null || _a === void 0 ? void 0 : _a.data) === null || _b === void 0 ? void 0 : _b[0];
|
|
2094
|
+
const attributes = row === null || row === void 0 ? void 0 : row["attributes"];
|
|
2095
|
+
if (attributes && typeof attributes === "object") {
|
|
2096
|
+
result.push(attributes);
|
|
2097
|
+
}
|
|
2098
|
+
}
|
|
2099
|
+
return result;
|
|
2100
|
+
}
|
|
2101
|
+
/**
|
|
2102
|
+
* The raw datapoint attributes a breaching sample carries. A sample from
|
|
2103
|
+
* a per-series query row keeps the datapoint's full attribute map under
|
|
2104
|
+
* `attributes`; a formula row carries only its group attributes there.
|
|
2105
|
+
*/
|
|
2106
|
+
static getSampleRawAttributes(sample) {
|
|
2107
|
+
if (!sample || !sample.attributes) {
|
|
2108
|
+
return undefined;
|
|
2109
|
+
}
|
|
2110
|
+
const nested = sample.attributes["attributes"];
|
|
2111
|
+
if (nested && typeof nested === "object" && !Array.isArray(nested)) {
|
|
2112
|
+
return nested;
|
|
2113
|
+
}
|
|
2114
|
+
return sample.attributes;
|
|
2115
|
+
}
|
|
2116
|
+
/**
|
|
2117
|
+
* The rows of a platform's "Affected Resources" list for the matched
|
|
2118
|
+
* criteria, from whichever source measured what the criteria compared:
|
|
2119
|
+
* the per-series matches of a grouped monitor, else the raw scan of the
|
|
2120
|
+
* criteria's own query. Null when neither applies (an ungrouped formula
|
|
2121
|
+
* has no per-resource values to list).
|
|
2122
|
+
*/
|
|
2123
|
+
static getPlatformAffectedRows(input) {
|
|
2124
|
+
var _a, _b, _c, _d;
|
|
2125
|
+
if (input.perSeriesMatches && input.perSeriesMatches.length > 0) {
|
|
2126
|
+
const queryCount = ((_b = (_a = MonitorStep.getMetricsViewConfig(input.monitorStep)) === null || _a === void 0 ? void 0 : _a.queryConfigs) === null || _b === void 0 ? void 0 : _b.length) || 0;
|
|
2127
|
+
return MonitorCriteriaEvaluator.buildSeriesAffectedRows({
|
|
2128
|
+
perSeriesMatches: input.perSeriesMatches,
|
|
2129
|
+
worstIsLowest: input.breach.worstIsLowest,
|
|
2130
|
+
toIdentity: input.toIdentity,
|
|
2131
|
+
withContext: input.withContext,
|
|
2132
|
+
namesObject: input.namesObject,
|
|
2133
|
+
targetAlias: (_c = input.target) === null || _c === void 0 ? void 0 : _c.alias,
|
|
2134
|
+
seriesContextAttributes: (fingerprint) => {
|
|
2135
|
+
return MonitorCriteriaEvaluator.getSeriesQueryRowAttributes({
|
|
2136
|
+
seriesBreakdown: input.metricResponse.seriesBreakdown,
|
|
2137
|
+
fingerprint: fingerprint,
|
|
2138
|
+
queryCount: queryCount,
|
|
2139
|
+
});
|
|
2140
|
+
},
|
|
2141
|
+
});
|
|
2142
|
+
}
|
|
2143
|
+
if (!input.breakdown || input.breakdown.affectedResources.length === 0) {
|
|
2144
|
+
return null;
|
|
2145
|
+
}
|
|
2146
|
+
return MonitorCriteriaEvaluator.buildScanAffectedRows({
|
|
2147
|
+
platform: input.platform,
|
|
2148
|
+
breakdown: input.breakdown,
|
|
2149
|
+
breach: input.breach,
|
|
2150
|
+
comparisonUnit: (_d = input.target) === null || _d === void 0 ? void 0 : _d.comparisonUnit,
|
|
2151
|
+
});
|
|
1482
2152
|
}
|
|
1483
2153
|
/*
|
|
1484
2154
|
* One Kubernetes resource as an "Affected Resources" list item.
|
|
@@ -1553,247 +2223,372 @@ ${contextBlock}
|
|
|
1553
2223
|
};
|
|
1554
2224
|
}
|
|
1555
2225
|
static async buildKubernetesRootCauseContext(input) {
|
|
1556
|
-
var _a;
|
|
2226
|
+
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
1557
2227
|
const metricResponse = input.dataToProcess;
|
|
1558
|
-
const
|
|
1559
|
-
|
|
2228
|
+
const target = MonitorCriteriaEvaluator.resolveCriteriaMetricTarget({
|
|
2229
|
+
criteriaInstance: input.criteriaInstance,
|
|
2230
|
+
monitorStep: input.monitorStep,
|
|
2231
|
+
metricResponse: metricResponse,
|
|
2232
|
+
});
|
|
2233
|
+
const breakdown = MonitorCriteriaEvaluator.selectPlatformBreakdown({
|
|
2234
|
+
breakdowns: metricResponse.kubernetesResourceBreakdowns,
|
|
2235
|
+
legacyBreakdown: metricResponse.kubernetesResourceBreakdown,
|
|
2236
|
+
target: target,
|
|
2237
|
+
});
|
|
2238
|
+
const hasSeries = Boolean(input.perSeriesMatches && input.perSeriesMatches.length > 0);
|
|
2239
|
+
/*
|
|
2240
|
+
* Nothing to say only when there is neither a list nor a monitor to
|
|
2241
|
+
* describe. An ungrouped formula criteria has no raw scan of its own
|
|
2242
|
+
* and no series, but its cluster and formula are still worth naming.
|
|
2243
|
+
*/
|
|
2244
|
+
if (!breakdown &&
|
|
2245
|
+
!hasSeries &&
|
|
2246
|
+
!((_a = input.monitorStep.data) === null || _a === void 0 ? void 0 : _a.kubernetesMonitor)) {
|
|
1560
2247
|
return null;
|
|
1561
2248
|
}
|
|
2249
|
+
const clusterName = (breakdown === null || breakdown === void 0 ? void 0 : breakdown.clusterName) ||
|
|
2250
|
+
((_c = (_b = input.monitorStep.data) === null || _b === void 0 ? void 0 : _b.kubernetesMonitor) === null || _c === void 0 ? void 0 : _c.clusterIdentifier) ||
|
|
2251
|
+
"Unknown";
|
|
2252
|
+
/*
|
|
2253
|
+
* The metric the analysis below reasons about: the criteria's own
|
|
2254
|
+
* query, or a formula's numerator. Without a criteria to go on, the
|
|
2255
|
+
* breakdown's metric, as before.
|
|
2256
|
+
*/
|
|
2257
|
+
const analysisMetricName = MonitorCriteriaEvaluator.getAnalysisMetricName(target) ||
|
|
2258
|
+
(breakdown === null || breakdown === void 0 ? void 0 : breakdown.metricName) ||
|
|
2259
|
+
"";
|
|
1562
2260
|
const sections = [];
|
|
1563
2261
|
// Cluster context
|
|
1564
2262
|
const clusterDetails = [];
|
|
1565
|
-
clusterDetails.push(`- Cluster: ${
|
|
1566
|
-
clusterDetails.push(
|
|
1567
|
-
|
|
1568
|
-
|
|
2263
|
+
clusterDetails.push(`- Cluster: ${clusterName}`);
|
|
2264
|
+
clusterDetails.push(...MonitorCriteriaEvaluator.describeCriteriaMetric({
|
|
2265
|
+
platform: "kubernetes",
|
|
2266
|
+
target: target,
|
|
2267
|
+
breakdown: breakdown,
|
|
2268
|
+
}));
|
|
2269
|
+
/*
|
|
2270
|
+
* The worker records the query's attribute filters under the stored,
|
|
2271
|
+
* `resource.`-prefixed key; the bare key never occurs, which is why
|
|
2272
|
+
* this line never rendered.
|
|
2273
|
+
*/
|
|
2274
|
+
const namespaceFilter = (breakdown === null || breakdown === void 0 ? void 0 : breakdown.attributes["resource.k8s.namespace.name"]) ||
|
|
2275
|
+
(breakdown === null || breakdown === void 0 ? void 0 : breakdown.attributes["k8s.namespace.name"]) ||
|
|
2276
|
+
((_f = (_e = (_d = input.monitorStep.data) === null || _d === void 0 ? void 0 : _d.kubernetesMonitor) === null || _e === void 0 ? void 0 : _e.resourceFilters) === null || _f === void 0 ? void 0 : _f.namespace);
|
|
2277
|
+
if (namespaceFilter) {
|
|
2278
|
+
clusterDetails.push(`- Namespace: ${namespaceFilter}`);
|
|
1569
2279
|
}
|
|
1570
2280
|
sections.push(`**Kubernetes Cluster Details**\n${clusterDetails.join("\n")}`);
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
|
|
1578
|
-
|
|
1579
|
-
|
|
1580
|
-
|
|
1581
|
-
|
|
1582
|
-
|
|
1583
|
-
|
|
1584
|
-
|
|
1585
|
-
|
|
1586
|
-
|
|
1587
|
-
|
|
1588
|
-
|
|
1589
|
-
|
|
1590
|
-
|
|
1591
|
-
|
|
1592
|
-
|
|
1593
|
-
|
|
1594
|
-
|
|
1595
|
-
|
|
1596
|
-
|
|
1597
|
-
|
|
1598
|
-
|
|
1599
|
-
|
|
1600
|
-
|
|
1601
|
-
|
|
1602
|
-
|
|
1603
|
-
|
|
1604
|
-
|
|
1605
|
-
|
|
1606
|
-
|
|
1607
|
-
|
|
1608
|
-
|
|
1609
|
-
|
|
1610
|
-
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
|
|
1614
|
-
|
|
1615
|
-
|
|
1616
|
-
|
|
1617
|
-
|
|
1618
|
-
|
|
1619
|
-
}),
|
|
2281
|
+
/*
|
|
2282
|
+
* Keep the rows that satisfy the criteria that just matched, worst
|
|
2283
|
+
* first — NOT simply the non-zero rows. k8s-node-not-ready fires on
|
|
2284
|
+
* `k8s.node.condition_ready = 0`, so the zero rows are the NotReady
|
|
2285
|
+
* nodes; the old hardcoded `> 0` dropped exactly those and named a
|
|
2286
|
+
* healthy node in the analysis below.
|
|
2287
|
+
*/
|
|
2288
|
+
const breach = MonitorCriteriaEvaluator.getAffectedResourceBreachPredicate({
|
|
2289
|
+
criteriaInstance: input.criteriaInstance,
|
|
2290
|
+
floorEqualityFiresOnFall: true,
|
|
2291
|
+
});
|
|
2292
|
+
const rows = MonitorCriteriaEvaluator.getPlatformAffectedRows({
|
|
2293
|
+
platform: "kubernetes",
|
|
2294
|
+
perSeriesMatches: input.perSeriesMatches,
|
|
2295
|
+
namesObject: (identity) => {
|
|
2296
|
+
return Boolean(identity.containerName ||
|
|
2297
|
+
identity.podName ||
|
|
2298
|
+
identity.workloadName ||
|
|
2299
|
+
identity.nodeName ||
|
|
2300
|
+
identity.namespace);
|
|
2301
|
+
},
|
|
2302
|
+
metricResponse: metricResponse,
|
|
2303
|
+
monitorStep: input.monitorStep,
|
|
2304
|
+
target: target,
|
|
2305
|
+
breakdown: breakdown,
|
|
2306
|
+
breach: breach,
|
|
2307
|
+
toIdentity: PlatformResourceIdentity.kubernetes,
|
|
2308
|
+
withContext: PlatformResourceIdentity.withKubernetesContext,
|
|
2309
|
+
});
|
|
2310
|
+
if (!rows || rows.length === 0) {
|
|
2311
|
+
return sections.join("\n");
|
|
2312
|
+
}
|
|
2313
|
+
// Show top 10 affected resources
|
|
2314
|
+
const rowsToShow = rows.slice(0, AffectedResourceList.MAX_ENTRIES);
|
|
2315
|
+
sections.push(AffectedResourceList.render({
|
|
2316
|
+
heading: "Affected Resources",
|
|
2317
|
+
overflowNoun: "affected resources",
|
|
2318
|
+
totalCount: rows.length,
|
|
2319
|
+
entries: rowsToShow.map((row) => {
|
|
2320
|
+
return row.seriesLabels
|
|
2321
|
+
? MonitorCriteriaEvaluator.getSeriesLabelEntry({
|
|
2322
|
+
labels: row.seriesLabels,
|
|
2323
|
+
value: MonitorCriteriaEvaluator.renderAffectedRowValue(row),
|
|
2324
|
+
})
|
|
2325
|
+
: MonitorCriteriaEvaluator.getKubernetesAffectedResourceEntry({
|
|
2326
|
+
resource: row.identity,
|
|
2327
|
+
clusterName: clusterName,
|
|
2328
|
+
value: MonitorCriteriaEvaluator.renderAffectedRowValue(row),
|
|
1620
2329
|
});
|
|
1621
|
-
|
|
1622
|
-
|
|
1623
|
-
|
|
1624
|
-
|
|
1625
|
-
|
|
1626
|
-
|
|
2330
|
+
}),
|
|
2331
|
+
}));
|
|
2332
|
+
const topRow = rowsToShow[0];
|
|
2333
|
+
const topResource = Object.assign(Object.assign({}, topRow.identity), { metricValue: (_g = topRow.value) !== null && _g !== void 0 ? _g : 0 });
|
|
2334
|
+
/*
|
|
2335
|
+
* Add root cause analysis based on metric type — unless the worst row
|
|
2336
|
+
* is a series that matched with no data at all, or one valued by a
|
|
2337
|
+
* different filter than the one analysed, which no sentence below
|
|
2338
|
+
* ("memory usage is at ...") can describe.
|
|
2339
|
+
*/
|
|
2340
|
+
const analysis = topRow.value === null || topRow.valueNote
|
|
2341
|
+
? null
|
|
2342
|
+
: MonitorCriteriaEvaluator.buildKubernetesRootCauseAnalysis({
|
|
2343
|
+
breakdown: {
|
|
2344
|
+
clusterName: clusterName,
|
|
2345
|
+
metricName: analysisMetricName,
|
|
2346
|
+
metricFriendlyName: ((target === null || target === void 0 ? void 0 : target.isFormula) ? target.displayName : undefined) ||
|
|
2347
|
+
((breakdown === null || breakdown === void 0 ? void 0 : breakdown.metricName) === analysisMetricName
|
|
2348
|
+
? breakdown.metricFriendlyName
|
|
2349
|
+
: undefined) ||
|
|
2350
|
+
MonitorCriteriaEvaluator.getPlatformMetricFriendlyName({
|
|
2351
|
+
platform: "kubernetes",
|
|
2352
|
+
metricName: analysisMetricName,
|
|
2353
|
+
}) ||
|
|
2354
|
+
analysisMetricName,
|
|
2355
|
+
affectedResources: [],
|
|
2356
|
+
attributes: (breakdown === null || breakdown === void 0 ? void 0 : breakdown.attributes) || {},
|
|
2357
|
+
metricUnit: breakdown === null || breakdown === void 0 ? void 0 : breakdown.metricUnit,
|
|
2358
|
+
},
|
|
2359
|
+
topResource: topResource,
|
|
2360
|
+
topResourceValue: topRow.formattedValue,
|
|
2361
|
+
target: target,
|
|
1627
2362
|
});
|
|
1628
|
-
|
|
1629
|
-
|
|
1630
|
-
|
|
1631
|
-
|
|
1632
|
-
|
|
1633
|
-
|
|
1634
|
-
|
|
1635
|
-
|
|
1636
|
-
|
|
1637
|
-
|
|
1638
|
-
|
|
1639
|
-
logAttributes["resource.k8s.cluster.name"] = breakdown.clusterName;
|
|
1640
|
-
}
|
|
1641
|
-
if (topResource.podName) {
|
|
1642
|
-
logAttributes["resource.k8s.pod.name"] = topResource.podName;
|
|
1643
|
-
}
|
|
1644
|
-
if (topResource.containerName) {
|
|
1645
|
-
logAttributes["resource.k8s.container.name"] =
|
|
1646
|
-
topResource.containerName;
|
|
1647
|
-
}
|
|
1648
|
-
if (topResource.namespace) {
|
|
1649
|
-
logAttributes["resource.k8s.namespace.name"] =
|
|
1650
|
-
topResource.namespace;
|
|
1651
|
-
}
|
|
1652
|
-
const now = OneUptimeDate.getCurrentDate();
|
|
1653
|
-
const fifteenMinutesAgo = OneUptimeDate.addRemoveMinutes(now, -15);
|
|
1654
|
-
const logs = await LogAggregationService.getExportLogs({
|
|
1655
|
-
projectId: input.monitor.projectId,
|
|
1656
|
-
startTime: fifteenMinutesAgo,
|
|
1657
|
-
endTime: now,
|
|
1658
|
-
limit: 50,
|
|
1659
|
-
attributes: logAttributes,
|
|
1660
|
-
});
|
|
1661
|
-
if (logs.length > 0) {
|
|
1662
|
-
const logLines = logs.map((log) => {
|
|
1663
|
-
const timestamp = log["time"] ? String(log["time"]) : "";
|
|
1664
|
-
const severity = log["severityText"]
|
|
1665
|
-
? String(log["severityText"])
|
|
1666
|
-
: "INFO";
|
|
1667
|
-
const body = log["body"] ? String(log["body"]) : "";
|
|
1668
|
-
return `\`${timestamp}\` **${severity}** ${body}`;
|
|
1669
|
-
});
|
|
1670
|
-
sections.push(`\n\n**Recent Container Logs** (${topResource.podName || "unknown pod"} / ${topResource.containerName || "unknown container"}, last 15 minutes)\n\n${logLines.join("\n\n")}`);
|
|
1671
|
-
}
|
|
2363
|
+
if (analysis) {
|
|
2364
|
+
sections.push(`\n\n**Root Cause Analysis**\n${analysis}`);
|
|
2365
|
+
}
|
|
2366
|
+
// Fetch recent container logs for the top affected resource during CrashLoopBackOff
|
|
2367
|
+
if ((analysisMetricName === "k8s.container.restarts" ||
|
|
2368
|
+
analysisMetricName.includes("restart")) &&
|
|
2369
|
+
input.monitor.projectId) {
|
|
2370
|
+
try {
|
|
2371
|
+
const logAttributes = {};
|
|
2372
|
+
if (clusterName) {
|
|
2373
|
+
logAttributes["resource.k8s.cluster.name"] = clusterName;
|
|
1672
2374
|
}
|
|
1673
|
-
|
|
1674
|
-
|
|
1675
|
-
|
|
1676
|
-
|
|
1677
|
-
|
|
1678
|
-
|
|
2375
|
+
if (topResource.podName) {
|
|
2376
|
+
logAttributes["resource.k8s.pod.name"] = topResource.podName;
|
|
2377
|
+
}
|
|
2378
|
+
if (topResource.containerName) {
|
|
2379
|
+
logAttributes["resource.k8s.container.name"] =
|
|
2380
|
+
topResource.containerName;
|
|
1679
2381
|
}
|
|
2382
|
+
if (topResource.namespace) {
|
|
2383
|
+
logAttributes["resource.k8s.namespace.name"] = topResource.namespace;
|
|
2384
|
+
}
|
|
2385
|
+
const now = OneUptimeDate.getCurrentDate();
|
|
2386
|
+
const fifteenMinutesAgo = OneUptimeDate.addRemoveMinutes(now, -15);
|
|
2387
|
+
const logs = await LogAggregationService.getExportLogs({
|
|
2388
|
+
projectId: input.monitor.projectId,
|
|
2389
|
+
startTime: fifteenMinutesAgo,
|
|
2390
|
+
endTime: now,
|
|
2391
|
+
limit: 50,
|
|
2392
|
+
attributes: logAttributes,
|
|
2393
|
+
});
|
|
2394
|
+
if (logs.length > 0) {
|
|
2395
|
+
const logLines = logs.map((log) => {
|
|
2396
|
+
const timestamp = log["time"] ? String(log["time"]) : "";
|
|
2397
|
+
const severity = log["severityText"]
|
|
2398
|
+
? String(log["severityText"])
|
|
2399
|
+
: "INFO";
|
|
2400
|
+
const body = log["body"] ? String(log["body"]) : "";
|
|
2401
|
+
return `\`${timestamp}\` **${severity}** ${body}`;
|
|
2402
|
+
});
|
|
2403
|
+
sections.push(`\n\n**Recent Container Logs** (${topResource.podName || "unknown pod"} / ${topResource.containerName || "unknown container"}, last 15 minutes)\n\n${logLines.join("\n\n")}`);
|
|
2404
|
+
}
|
|
2405
|
+
}
|
|
2406
|
+
catch (err) {
|
|
2407
|
+
const k8sLogAttributes = {
|
|
2408
|
+
projectId: (_h = input.monitor.projectId) === null || _h === void 0 ? void 0 : _h.toString(),
|
|
2409
|
+
};
|
|
2410
|
+
logger.error("Failed to fetch container logs for root cause context", k8sLogAttributes);
|
|
2411
|
+
logger.error(err, k8sLogAttributes);
|
|
1680
2412
|
}
|
|
1681
2413
|
}
|
|
1682
2414
|
return sections.join("\n");
|
|
1683
2415
|
}
|
|
1684
|
-
|
|
1685
|
-
|
|
1686
|
-
|
|
2416
|
+
/**
|
|
2417
|
+
* The "- Metric:" line of a telemetry resource's details block: what
|
|
2418
|
+
* the matched criteria actually compared.
|
|
2419
|
+
*
|
|
2420
|
+
* It used to name `queryConfigs[0]` unconditionally, so a criteria on a
|
|
2421
|
+
* formula — Host CPU busy `(host_cpu_user + host_cpu_system) * 100`,
|
|
2422
|
+
* Docker restarts `max - min` — was reported as its first operand. The
|
|
2423
|
+
* metric context MetricMonitorCriteria records at evaluation time
|
|
2424
|
+
* already says whether the criteria resolved to a query or a formula
|
|
2425
|
+
* (including its fall back to the first query when the alias names
|
|
2426
|
+
* nothing), so the line is read from there.
|
|
2427
|
+
*
|
|
2428
|
+
* A formula is named by its legend, which is what the threshold was
|
|
2429
|
+
* written against ("CPU Busy (%)"); its expression and the metric behind
|
|
2430
|
+
* each variable are spelled out in the Metric Details below. With no
|
|
2431
|
+
* metric context — a criteria with no metric-value filter — the step's
|
|
2432
|
+
* first query is named, as before.
|
|
2433
|
+
*/
|
|
2434
|
+
static describeCriteriaMetricLine(input) {
|
|
2435
|
+
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
2436
|
+
const ctx = input.ctx;
|
|
2437
|
+
if (ctx === null || ctx === void 0 ? void 0 : ctx.isFormula) {
|
|
2438
|
+
const formula = (((_a = input.metricViewConfig) === null || _a === void 0 ? void 0 : _a.formulaConfigs) || []).find((f) => {
|
|
2439
|
+
var _a;
|
|
2440
|
+
return ((_a = f.metricAliasData) === null || _a === void 0 ? void 0 : _a.metricVariable) === ctx.alias;
|
|
2441
|
+
});
|
|
2442
|
+
const legend = (((_b = formula === null || formula === void 0 ? void 0 : formula.metricAliasData) === null || _b === void 0 ? void 0 : _b.legend) ||
|
|
2443
|
+
((_c = formula === null || formula === void 0 ? void 0 : formula.metricAliasData) === null || _c === void 0 ? void 0 : _c.title) ||
|
|
2444
|
+
"").trim();
|
|
2445
|
+
if (legend && legend !== ctx.alias) {
|
|
2446
|
+
return `- Metric: ${legend}`;
|
|
2447
|
+
}
|
|
2448
|
+
return `- Metric: \`${ctx.alias}\` (formula)`;
|
|
2449
|
+
}
|
|
2450
|
+
if (ctx === null || ctx === void 0 ? void 0 : ctx.metricName) {
|
|
2451
|
+
return `- Metric: \`${ctx.metricName}\``;
|
|
2452
|
+
}
|
|
2453
|
+
const firstQueryMetricName = (_h = (_g = (_f = (_e = (_d = input.metricViewConfig) === null || _d === void 0 ? void 0 : _d.queryConfigs) === null || _e === void 0 ? void 0 : _e[0]) === null || _f === void 0 ? void 0 : _f.metricQueryData) === null || _g === void 0 ? void 0 : _g.filterData) === null || _h === void 0 ? void 0 : _h.metricName;
|
|
2454
|
+
return firstQueryMetricName
|
|
2455
|
+
? `- Metric: \`${firstQueryMetricName}\``
|
|
2456
|
+
: null;
|
|
2457
|
+
}
|
|
2458
|
+
/**
|
|
2459
|
+
* Root-cause context for a telemetry monitor that watches one host,
|
|
2460
|
+
* container set or device fleet: the resource it is scoped to, then the
|
|
2461
|
+
* same Metric Details and Breaching Samples a Metrics monitor gets.
|
|
2462
|
+
*
|
|
2463
|
+
* These monitors used to follow the identity lines with a "Metric
|
|
2464
|
+
* Summary" that only counted the data points in each result — one line
|
|
2465
|
+
* per query AND per formula, so the Host CPU template printed three
|
|
2466
|
+
* identical "- 5 metric data point(s) returned" lines and never the
|
|
2467
|
+
* value that breached. MetricMonitorCriteria fills the filter's metric
|
|
2468
|
+
* context for every metric-backed monitor type, so the unit, formula,
|
|
2469
|
+
* components and unit-formatted samples were there all along.
|
|
2470
|
+
*
|
|
2471
|
+
* `identityLines` is null when the step carries no config for the
|
|
2472
|
+
* monitor type; the metric details are still rendered from the context.
|
|
2473
|
+
*/
|
|
2474
|
+
static buildTelemetryResourceRootCauseContext(input) {
|
|
1687
2475
|
const sections = [];
|
|
2476
|
+
if (input.identityLines) {
|
|
2477
|
+
const metricLine = MonitorCriteriaEvaluator.describeCriteriaMetricLine({
|
|
2478
|
+
ctx: MonitorCriteriaEvaluator.getMetricCriteriaContext(input.criteriaInstance),
|
|
2479
|
+
metricViewConfig: MonitorStep.getMetricsViewConfig(input.monitorStep),
|
|
2480
|
+
});
|
|
2481
|
+
const lines = metricLine
|
|
2482
|
+
? [...input.identityLines, metricLine]
|
|
2483
|
+
: input.identityLines;
|
|
2484
|
+
sections.push(`**${input.heading}**\n${lines.join("\n")}`);
|
|
2485
|
+
}
|
|
2486
|
+
const metricDetails = input.criteriaInstance
|
|
2487
|
+
? MonitorCriteriaEvaluator.buildMetricRootCauseContext({
|
|
2488
|
+
criteriaInstance: input.criteriaInstance,
|
|
2489
|
+
monitor: input.monitor,
|
|
2490
|
+
monitorStep: input.monitorStep,
|
|
2491
|
+
})
|
|
2492
|
+
: null;
|
|
2493
|
+
if (metricDetails) {
|
|
2494
|
+
sections.push(sections.length > 0 ? `\n\n${metricDetails}` : metricDetails);
|
|
2495
|
+
}
|
|
2496
|
+
return sections.length > 0 ? sections.join("\n") : null;
|
|
2497
|
+
}
|
|
2498
|
+
static buildDockerRootCauseContext(input) {
|
|
2499
|
+
var _a, _b, _c;
|
|
1688
2500
|
// Docker host context
|
|
1689
2501
|
const dockerMonitor = (_a = input.monitorStep.data) === null || _a === void 0 ? void 0 : _a.dockerMonitor;
|
|
2502
|
+
let hostDetails = null;
|
|
1690
2503
|
if (dockerMonitor) {
|
|
1691
|
-
|
|
1692
|
-
hostDetails.push(`- Host: ${dockerMonitor.hostIdentifier || "Unknown"}`);
|
|
2504
|
+
hostDetails = [`- Host: ${dockerMonitor.hostIdentifier || "Unknown"}`];
|
|
1693
2505
|
if ((_b = dockerMonitor.containerFilters) === null || _b === void 0 ? void 0 : _b.containerName) {
|
|
1694
2506
|
hostDetails.push(`- Container Name Filter: ${dockerMonitor.containerFilters.containerName}`);
|
|
1695
2507
|
}
|
|
1696
2508
|
if ((_c = dockerMonitor.containerFilters) === null || _c === void 0 ? void 0 : _c.containerImage) {
|
|
1697
2509
|
hostDetails.push(`- Container Image Filter: ${dockerMonitor.containerFilters.containerImage}`);
|
|
1698
2510
|
}
|
|
1699
|
-
// Add metric name from the query config
|
|
1700
|
-
if (((_e = (_d = dockerMonitor.metricViewConfig) === null || _d === void 0 ? void 0 : _d.queryConfigs) === null || _e === void 0 ? void 0 : _e.length) > 0 &&
|
|
1701
|
-
dockerMonitor.metricViewConfig.queryConfigs[0]) {
|
|
1702
|
-
const metricName = (_g = (_f = dockerMonitor.metricViewConfig
|
|
1703
|
-
.queryConfigs[0].metricQueryData) === null || _f === void 0 ? void 0 : _f.filterData) === null || _g === void 0 ? void 0 : _g.metricName;
|
|
1704
|
-
if (metricName) {
|
|
1705
|
-
hostDetails.push(`- Metric: \`${metricName}\``);
|
|
1706
|
-
}
|
|
1707
|
-
}
|
|
1708
|
-
sections.push(`**Docker Host Details**\n${hostDetails.join("\n")}`);
|
|
1709
2511
|
}
|
|
1710
|
-
|
|
1711
|
-
|
|
1712
|
-
|
|
1713
|
-
|
|
1714
|
-
|
|
1715
|
-
|
|
1716
|
-
|
|
1717
|
-
}
|
|
1718
|
-
if (resultDetails.length > 0) {
|
|
1719
|
-
sections.push(`\n\n**Metric Summary**\n${resultDetails.join("\n")}`);
|
|
1720
|
-
}
|
|
1721
|
-
}
|
|
1722
|
-
return sections.length > 0 ? sections.join("\n") : null;
|
|
2512
|
+
return MonitorCriteriaEvaluator.buildTelemetryResourceRootCauseContext({
|
|
2513
|
+
heading: "Docker Host Details",
|
|
2514
|
+
identityLines: hostDetails,
|
|
2515
|
+
monitor: input.monitor,
|
|
2516
|
+
monitorStep: input.monitorStep,
|
|
2517
|
+
criteriaInstance: input.criteriaInstance,
|
|
2518
|
+
});
|
|
1723
2519
|
}
|
|
1724
2520
|
static buildHostRootCauseContext(input) {
|
|
1725
|
-
var _a
|
|
1726
|
-
const metricResponse = input.dataToProcess;
|
|
1727
|
-
const sections = [];
|
|
2521
|
+
var _a;
|
|
1728
2522
|
// Host context
|
|
1729
2523
|
const hostMonitor = (_a = input.monitorStep.data) === null || _a === void 0 ? void 0 : _a.hostMonitor;
|
|
1730
|
-
|
|
1731
|
-
|
|
1732
|
-
|
|
1733
|
-
|
|
1734
|
-
|
|
1735
|
-
|
|
1736
|
-
|
|
1737
|
-
|
|
1738
|
-
|
|
1739
|
-
hostDetails.push(`- Metric: \`${metricName}\``);
|
|
1740
|
-
}
|
|
1741
|
-
}
|
|
1742
|
-
sections.push(`**Host Details**\n${hostDetails.join("\n")}`);
|
|
1743
|
-
}
|
|
1744
|
-
// Metric results summary
|
|
1745
|
-
if (metricResponse.metricResult && metricResponse.metricResult.length > 0) {
|
|
1746
|
-
const resultDetails = [];
|
|
1747
|
-
for (const result of metricResponse.metricResult) {
|
|
1748
|
-
if (result.data && result.data.length > 0) {
|
|
1749
|
-
resultDetails.push(`- ${result.data.length} metric data point(s) returned`);
|
|
1750
|
-
}
|
|
1751
|
-
}
|
|
1752
|
-
if (resultDetails.length > 0) {
|
|
1753
|
-
sections.push(`\n\n**Metric Summary**\n${resultDetails.join("\n")}`);
|
|
1754
|
-
}
|
|
1755
|
-
}
|
|
1756
|
-
return sections.length > 0 ? sections.join("\n") : null;
|
|
2524
|
+
return MonitorCriteriaEvaluator.buildTelemetryResourceRootCauseContext({
|
|
2525
|
+
heading: "Host Details",
|
|
2526
|
+
identityLines: hostMonitor
|
|
2527
|
+
? [`- Host: ${hostMonitor.hostIdentifier || "Unknown"}`]
|
|
2528
|
+
: null,
|
|
2529
|
+
monitor: input.monitor,
|
|
2530
|
+
monitorStep: input.monitorStep,
|
|
2531
|
+
criteriaInstance: input.criteriaInstance,
|
|
2532
|
+
});
|
|
1757
2533
|
}
|
|
1758
2534
|
static buildPodmanRootCauseContext(input) {
|
|
1759
|
-
var _a, _b, _c
|
|
1760
|
-
const metricResponse = input.dataToProcess;
|
|
1761
|
-
const sections = [];
|
|
2535
|
+
var _a, _b, _c;
|
|
1762
2536
|
// Podman host context
|
|
1763
2537
|
const podmanMonitor = (_a = input.monitorStep.data) === null || _a === void 0 ? void 0 : _a.podmanMonitor;
|
|
2538
|
+
let hostDetails = null;
|
|
1764
2539
|
if (podmanMonitor) {
|
|
1765
|
-
|
|
1766
|
-
hostDetails.push(`- Host: ${podmanMonitor.hostIdentifier || "Unknown"}`);
|
|
2540
|
+
hostDetails = [`- Host: ${podmanMonitor.hostIdentifier || "Unknown"}`];
|
|
1767
2541
|
if ((_b = podmanMonitor.containerFilters) === null || _b === void 0 ? void 0 : _b.containerName) {
|
|
1768
2542
|
hostDetails.push(`- Container Name Filter: ${podmanMonitor.containerFilters.containerName}`);
|
|
1769
2543
|
}
|
|
1770
2544
|
if ((_c = podmanMonitor.containerFilters) === null || _c === void 0 ? void 0 : _c.containerImage) {
|
|
1771
2545
|
hostDetails.push(`- Container Image Filter: ${podmanMonitor.containerFilters.containerImage}`);
|
|
1772
2546
|
}
|
|
1773
|
-
// Add metric name from the query config
|
|
1774
|
-
if (((_e = (_d = podmanMonitor.metricViewConfig) === null || _d === void 0 ? void 0 : _d.queryConfigs) === null || _e === void 0 ? void 0 : _e.length) > 0 &&
|
|
1775
|
-
podmanMonitor.metricViewConfig.queryConfigs[0]) {
|
|
1776
|
-
const metricName = (_g = (_f = podmanMonitor.metricViewConfig
|
|
1777
|
-
.queryConfigs[0].metricQueryData) === null || _f === void 0 ? void 0 : _f.filterData) === null || _g === void 0 ? void 0 : _g.metricName;
|
|
1778
|
-
if (metricName) {
|
|
1779
|
-
hostDetails.push(`- Metric: \`${metricName}\``);
|
|
1780
|
-
}
|
|
1781
|
-
}
|
|
1782
|
-
sections.push(`**Podman Host Details**\n${hostDetails.join("\n")}`);
|
|
1783
2547
|
}
|
|
1784
|
-
|
|
1785
|
-
|
|
1786
|
-
|
|
1787
|
-
|
|
1788
|
-
|
|
1789
|
-
|
|
1790
|
-
|
|
2548
|
+
return MonitorCriteriaEvaluator.buildTelemetryResourceRootCauseContext({
|
|
2549
|
+
heading: "Podman Host Details",
|
|
2550
|
+
identityLines: hostDetails,
|
|
2551
|
+
monitor: input.monitor,
|
|
2552
|
+
monitorStep: input.monitorStep,
|
|
2553
|
+
criteriaInstance: input.criteriaInstance,
|
|
2554
|
+
});
|
|
2555
|
+
}
|
|
2556
|
+
static buildIoTRootCauseContext(input) {
|
|
2557
|
+
var _a, _b, _c, _d, _e, _f;
|
|
2558
|
+
// IoT fleet / device context
|
|
2559
|
+
const iotMonitor = (_a = input.monitorStep.data) === null || _a === void 0 ? void 0 : _a.iotMonitor;
|
|
2560
|
+
let deviceDetails = null;
|
|
2561
|
+
if (iotMonitor) {
|
|
2562
|
+
deviceDetails = [`- Fleet: ${iotMonitor.fleetIdentifier || "Unknown"}`];
|
|
2563
|
+
/*
|
|
2564
|
+
* The device that breached. Every IoT template groups by the
|
|
2565
|
+
* `device.id` label, so the matched series names it; an ungrouped
|
|
2566
|
+
* monitor has no series labels and falls back to the step's own
|
|
2567
|
+
* device filter below.
|
|
2568
|
+
*/
|
|
2569
|
+
const breachingDeviceId = (_c = (_b = MonitorCriteriaEvaluator.getMetricCriteriaContext(input.criteriaInstance)) === null || _b === void 0 ? void 0 : _b.seriesLabels) === null || _c === void 0 ? void 0 : _c[IOT_DEVICE_ID_ATTRIBUTE_KEY];
|
|
2570
|
+
if (breachingDeviceId !== undefined &&
|
|
2571
|
+
breachingDeviceId !== null &&
|
|
2572
|
+
String(breachingDeviceId) !== "") {
|
|
2573
|
+
deviceDetails.push(`- Device: ${AffectedResourceList.code(String(breachingDeviceId))}`);
|
|
1791
2574
|
}
|
|
1792
|
-
if (
|
|
1793
|
-
|
|
2575
|
+
if ((_d = iotMonitor.resourceFilters) === null || _d === void 0 ? void 0 : _d.deviceId) {
|
|
2576
|
+
deviceDetails.push(`- Device ID Filter: ${iotMonitor.resourceFilters.deviceId}`);
|
|
2577
|
+
}
|
|
2578
|
+
if ((_e = iotMonitor.resourceFilters) === null || _e === void 0 ? void 0 : _e.deviceType) {
|
|
2579
|
+
deviceDetails.push(`- Device Type Filter: ${iotMonitor.resourceFilters.deviceType}`);
|
|
2580
|
+
}
|
|
2581
|
+
if ((_f = iotMonitor.resourceFilters) === null || _f === void 0 ? void 0 : _f.scope) {
|
|
2582
|
+
deviceDetails.push(`- Scope Filter: ${iotMonitor.resourceFilters.scope}`);
|
|
1794
2583
|
}
|
|
1795
2584
|
}
|
|
1796
|
-
return
|
|
2585
|
+
return MonitorCriteriaEvaluator.buildTelemetryResourceRootCauseContext({
|
|
2586
|
+
heading: "IoT Device Details",
|
|
2587
|
+
identityLines: deviceDetails,
|
|
2588
|
+
monitor: input.monitor,
|
|
2589
|
+
monitorStep: input.monitorStep,
|
|
2590
|
+
criteriaInstance: input.criteriaInstance,
|
|
2591
|
+
});
|
|
1797
2592
|
}
|
|
1798
2593
|
/*
|
|
1799
2594
|
* What a Proxmox resource is, from the `pve.type` / `pve.scope` the
|
|
@@ -1865,87 +2660,100 @@ ${contextBlock}
|
|
|
1865
2660
|
};
|
|
1866
2661
|
}
|
|
1867
2662
|
static buildProxmoxRootCauseContext(input) {
|
|
1868
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _j;
|
|
2663
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k;
|
|
1869
2664
|
const metricResponse = input.dataToProcess;
|
|
1870
|
-
const breakdown = metricResponse.proxmoxResourceBreakdown;
|
|
1871
|
-
const sections = [];
|
|
1872
2665
|
// Proxmox cluster context
|
|
1873
2666
|
const proxmoxMonitor = (_a = input.monitorStep.data) === null || _a === void 0 ? void 0 : _a.proxmoxMonitor;
|
|
2667
|
+
const target = MonitorCriteriaEvaluator.resolveCriteriaMetricTarget({
|
|
2668
|
+
criteriaInstance: input.criteriaInstance,
|
|
2669
|
+
monitorStep: input.monitorStep,
|
|
2670
|
+
metricResponse: metricResponse,
|
|
2671
|
+
});
|
|
2672
|
+
const breakdown = MonitorCriteriaEvaluator.selectPlatformBreakdown({
|
|
2673
|
+
breakdowns: metricResponse.proxmoxResourceBreakdowns,
|
|
2674
|
+
legacyBreakdown: metricResponse.proxmoxResourceBreakdown,
|
|
2675
|
+
target: target,
|
|
2676
|
+
});
|
|
2677
|
+
const clusterName = (breakdown === null || breakdown === void 0 ? void 0 : breakdown.clusterName) || (proxmoxMonitor === null || proxmoxMonitor === void 0 ? void 0 : proxmoxMonitor.clusterIdentifier) || "Unknown";
|
|
2678
|
+
const sections = [];
|
|
1874
2679
|
if (proxmoxMonitor || breakdown) {
|
|
1875
2680
|
const clusterDetails = [];
|
|
1876
|
-
clusterDetails.push(`- Cluster: ${
|
|
1877
|
-
|
|
1878
|
-
|
|
1879
|
-
|
|
1880
|
-
|
|
1881
|
-
((_c = (_b = proxmoxMonitor.metricViewConfig) === null || _b === void 0 ? void 0 : _b.queryConfigs) === null || _c === void 0 ? void 0 : _c.
|
|
1882
|
-
|
|
1883
|
-
|
|
1884
|
-
.queryConfigs[0].metricQueryData) === null || _d === void 0 ? void 0 : _d.filterData) === null || _e === void 0 ? void 0 : _e.metricName;
|
|
1885
|
-
if (metricName) {
|
|
1886
|
-
clusterDetails.push(`- Metric: \`${metricName}\``);
|
|
1887
|
-
}
|
|
1888
|
-
}
|
|
1889
|
-
if ((_f = proxmoxMonitor === null || proxmoxMonitor === void 0 ? void 0 : proxmoxMonitor.resourceFilters) === null || _f === void 0 ? void 0 : _f.scope) {
|
|
2681
|
+
clusterDetails.push(`- Cluster: ${clusterName}`);
|
|
2682
|
+
clusterDetails.push(...MonitorCriteriaEvaluator.describeCriteriaMetric({
|
|
2683
|
+
platform: "proxmox",
|
|
2684
|
+
target: target,
|
|
2685
|
+
breakdown: breakdown,
|
|
2686
|
+
fallbackMetricName: (_f = (_e = (_d = (_c = (_b = proxmoxMonitor === null || proxmoxMonitor === void 0 ? void 0 : proxmoxMonitor.metricViewConfig) === null || _b === void 0 ? void 0 : _b.queryConfigs) === null || _c === void 0 ? void 0 : _c[0]) === null || _d === void 0 ? void 0 : _d.metricQueryData) === null || _e === void 0 ? void 0 : _e.filterData) === null || _f === void 0 ? void 0 : _f.metricName,
|
|
2687
|
+
}));
|
|
2688
|
+
if ((_g = proxmoxMonitor === null || proxmoxMonitor === void 0 ? void 0 : proxmoxMonitor.resourceFilters) === null || _g === void 0 ? void 0 : _g.scope) {
|
|
1890
2689
|
clusterDetails.push(`- Scope Filter: ${proxmoxMonitor.resourceFilters.scope}`);
|
|
1891
2690
|
}
|
|
1892
|
-
if ((
|
|
2691
|
+
if ((_h = proxmoxMonitor === null || proxmoxMonitor === void 0 ? void 0 : proxmoxMonitor.resourceFilters) === null || _h === void 0 ? void 0 : _h.pveId) {
|
|
1893
2692
|
clusterDetails.push(`- Resource ID Filter: ${proxmoxMonitor.resourceFilters.pveId}`);
|
|
1894
2693
|
}
|
|
1895
|
-
if ((
|
|
2694
|
+
if ((_j = proxmoxMonitor === null || proxmoxMonitor === void 0 ? void 0 : proxmoxMonitor.resourceFilters) === null || _j === void 0 ? void 0 : _j.nodeName) {
|
|
1896
2695
|
clusterDetails.push(`- Node Filter: ${proxmoxMonitor.resourceFilters.nodeName}`);
|
|
1897
2696
|
}
|
|
1898
|
-
if ((
|
|
2697
|
+
if ((_k = proxmoxMonitor === null || proxmoxMonitor === void 0 ? void 0 : proxmoxMonitor.resourceFilters) === null || _k === void 0 ? void 0 : _k.guestId) {
|
|
1899
2698
|
clusterDetails.push(`- Guest ID Filter: ${proxmoxMonitor.resourceFilters.guestId}`);
|
|
1900
2699
|
}
|
|
1901
2700
|
sections.push(`**Proxmox Cluster Details**\n${clusterDetails.join("\n")}`);
|
|
1902
2701
|
}
|
|
1903
2702
|
// Affected resources: a ranked list of kind, name and node
|
|
1904
2703
|
let renderedBreakdownList = false;
|
|
1905
|
-
|
|
1906
|
-
|
|
1907
|
-
|
|
1908
|
-
|
|
1909
|
-
|
|
1910
|
-
|
|
1911
|
-
|
|
1912
|
-
|
|
1913
|
-
|
|
1914
|
-
|
|
1915
|
-
|
|
1916
|
-
|
|
1917
|
-
|
|
1918
|
-
|
|
1919
|
-
|
|
1920
|
-
|
|
1921
|
-
|
|
1922
|
-
|
|
1923
|
-
|
|
1924
|
-
|
|
1925
|
-
|
|
1926
|
-
|
|
1927
|
-
|
|
1928
|
-
|
|
1929
|
-
|
|
1930
|
-
|
|
1931
|
-
|
|
1932
|
-
|
|
1933
|
-
|
|
1934
|
-
|
|
1935
|
-
|
|
1936
|
-
|
|
1937
|
-
|
|
1938
|
-
|
|
1939
|
-
|
|
1940
|
-
|
|
1941
|
-
|
|
1942
|
-
|
|
1943
|
-
|
|
2704
|
+
/*
|
|
2705
|
+
* The resources the matched criteria breached, worst first, top 10 —
|
|
2706
|
+
* NOT simply the non-zero rows. pve-node-offline fires on `pve_up < 1`,
|
|
2707
|
+
* so the zero rows ARE the down nodes; the old `> 0` listed every
|
|
2708
|
+
* healthy node under it instead.
|
|
2709
|
+
*/
|
|
2710
|
+
const rows = MonitorCriteriaEvaluator.getPlatformAffectedRows({
|
|
2711
|
+
platform: "proxmox",
|
|
2712
|
+
perSeriesMatches: input.perSeriesMatches,
|
|
2713
|
+
namesObject: (identity) => {
|
|
2714
|
+
return Boolean(identity.resourceId || identity.resourceName || identity.nodeName);
|
|
2715
|
+
},
|
|
2716
|
+
metricResponse: metricResponse,
|
|
2717
|
+
monitorStep: input.monitorStep,
|
|
2718
|
+
target: target,
|
|
2719
|
+
breakdown: breakdown,
|
|
2720
|
+
breach: MonitorCriteriaEvaluator.getAffectedResourceBreachPredicate({
|
|
2721
|
+
criteriaInstance: input.criteriaInstance,
|
|
2722
|
+
}),
|
|
2723
|
+
toIdentity: PlatformResourceIdentity.proxmox,
|
|
2724
|
+
withContext: PlatformResourceIdentity.withProxmoxContext,
|
|
2725
|
+
});
|
|
2726
|
+
/*
|
|
2727
|
+
* Skip the list when no row carries any identity label
|
|
2728
|
+
* (cluster-wide series) — it would add nothing.
|
|
2729
|
+
*/
|
|
2730
|
+
const hasIdentity = (rows || []).some((row) => {
|
|
2731
|
+
return Boolean(row.seriesLabels ||
|
|
2732
|
+
row.identity.resourceId ||
|
|
2733
|
+
row.identity.resourceName ||
|
|
2734
|
+
row.identity.nodeName);
|
|
2735
|
+
});
|
|
2736
|
+
if (rows && rows.length > 0 && hasIdentity) {
|
|
2737
|
+
sections.push(AffectedResourceList.render({
|
|
2738
|
+
heading: "Affected Resources",
|
|
2739
|
+
overflowNoun: "affected resources",
|
|
2740
|
+
totalCount: rows.length,
|
|
2741
|
+
entries: rows
|
|
2742
|
+
.slice(0, AffectedResourceList.MAX_ENTRIES)
|
|
2743
|
+
.map((row) => {
|
|
2744
|
+
return row.seriesLabels
|
|
2745
|
+
? MonitorCriteriaEvaluator.getSeriesLabelEntry({
|
|
2746
|
+
labels: row.seriesLabels,
|
|
2747
|
+
value: MonitorCriteriaEvaluator.renderAffectedRowValue(row),
|
|
2748
|
+
})
|
|
2749
|
+
: MonitorCriteriaEvaluator.getProxmoxAffectedResourceEntry({
|
|
2750
|
+
resource: row.identity,
|
|
2751
|
+
clusterName: clusterName,
|
|
2752
|
+
value: MonitorCriteriaEvaluator.renderAffectedRowValue(row),
|
|
1944
2753
|
});
|
|
1945
|
-
|
|
1946
|
-
|
|
1947
|
-
|
|
1948
|
-
}
|
|
2754
|
+
}),
|
|
2755
|
+
}));
|
|
2756
|
+
renderedBreakdownList = true;
|
|
1949
2757
|
}
|
|
1950
2758
|
// Metric results summary (fallback context when no list rendered)
|
|
1951
2759
|
if (!renderedBreakdownList &&
|
|
@@ -2072,102 +2880,111 @@ ${contextBlock}
|
|
|
2072
2880
|
};
|
|
2073
2881
|
}
|
|
2074
2882
|
static buildVMwareRootCauseContext(input) {
|
|
2075
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l;
|
|
2883
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m;
|
|
2076
2884
|
const metricResponse = input.dataToProcess;
|
|
2077
|
-
const breakdown = metricResponse.vmwareResourceBreakdown;
|
|
2078
|
-
const sections = [];
|
|
2079
2885
|
// vCenter context
|
|
2080
2886
|
const vmwareMonitor = (_a = input.monitorStep.data) === null || _a === void 0 ? void 0 : _a.vmwareMonitor;
|
|
2887
|
+
const target = MonitorCriteriaEvaluator.resolveCriteriaMetricTarget({
|
|
2888
|
+
criteriaInstance: input.criteriaInstance,
|
|
2889
|
+
monitorStep: input.monitorStep,
|
|
2890
|
+
metricResponse: metricResponse,
|
|
2891
|
+
});
|
|
2892
|
+
const breakdown = MonitorCriteriaEvaluator.selectPlatformBreakdown({
|
|
2893
|
+
breakdowns: metricResponse.vmwareResourceBreakdowns,
|
|
2894
|
+
legacyBreakdown: metricResponse.vmwareResourceBreakdown,
|
|
2895
|
+
target: target,
|
|
2896
|
+
});
|
|
2897
|
+
const vcenterName = (breakdown === null || breakdown === void 0 ? void 0 : breakdown.vcenterName) || (vmwareMonitor === null || vmwareMonitor === void 0 ? void 0 : vmwareMonitor.vcenterIdentifier) || "Unknown";
|
|
2898
|
+
const sections = [];
|
|
2081
2899
|
if (vmwareMonitor || breakdown) {
|
|
2082
2900
|
const vcenterDetails = [];
|
|
2083
|
-
vcenterDetails.push(`- vCenter: ${
|
|
2084
|
-
|
|
2085
|
-
|
|
2086
|
-
|
|
2087
|
-
|
|
2088
|
-
((_c = (_b = vmwareMonitor.metricViewConfig) === null || _b === void 0 ? void 0 : _b.queryConfigs) === null || _c === void 0 ? void 0 : _c.
|
|
2089
|
-
|
|
2090
|
-
const metricName = (_e = (_d = vmwareMonitor.metricViewConfig
|
|
2091
|
-
.queryConfigs[0].metricQueryData) === null || _d === void 0 ? void 0 : _d.filterData) === null || _e === void 0 ? void 0 : _e.metricName;
|
|
2092
|
-
if (metricName) {
|
|
2093
|
-
vcenterDetails.push(`- Metric: \`${metricName}\``);
|
|
2094
|
-
}
|
|
2095
|
-
}
|
|
2901
|
+
vcenterDetails.push(`- vCenter: ${vcenterName}`);
|
|
2902
|
+
vcenterDetails.push(...MonitorCriteriaEvaluator.describeCriteriaMetric({
|
|
2903
|
+
platform: "vmware",
|
|
2904
|
+
target: target,
|
|
2905
|
+
breakdown: breakdown,
|
|
2906
|
+
fallbackMetricName: (_f = (_e = (_d = (_c = (_b = vmwareMonitor === null || vmwareMonitor === void 0 ? void 0 : vmwareMonitor.metricViewConfig) === null || _b === void 0 ? void 0 : _b.queryConfigs) === null || _c === void 0 ? void 0 : _c[0]) === null || _d === void 0 ? void 0 : _d.metricQueryData) === null || _e === void 0 ? void 0 : _e.filterData) === null || _f === void 0 ? void 0 : _f.metricName,
|
|
2907
|
+
}));
|
|
2096
2908
|
/*
|
|
2097
2909
|
* The worker maps each resource filter to an equality on the
|
|
2098
2910
|
* matching `resource.vcenter.*` attribute; surface the same
|
|
2099
2911
|
* filters so the incident shows WHAT was scoped.
|
|
2100
2912
|
*/
|
|
2101
|
-
if ((
|
|
2913
|
+
if ((_g = vmwareMonitor === null || vmwareMonitor === void 0 ? void 0 : vmwareMonitor.resourceFilters) === null || _g === void 0 ? void 0 : _g.datacenterName) {
|
|
2102
2914
|
vcenterDetails.push(`- Datacenter Filter: ${vmwareMonitor.resourceFilters.datacenterName}`);
|
|
2103
2915
|
}
|
|
2104
|
-
if ((
|
|
2916
|
+
if ((_h = vmwareMonitor === null || vmwareMonitor === void 0 ? void 0 : vmwareMonitor.resourceFilters) === null || _h === void 0 ? void 0 : _h.clusterName) {
|
|
2105
2917
|
vcenterDetails.push(`- Cluster Filter: ${vmwareMonitor.resourceFilters.clusterName}`);
|
|
2106
2918
|
}
|
|
2107
|
-
if ((
|
|
2919
|
+
if ((_j = vmwareMonitor === null || vmwareMonitor === void 0 ? void 0 : vmwareMonitor.resourceFilters) === null || _j === void 0 ? void 0 : _j.hostName) {
|
|
2108
2920
|
vcenterDetails.push(`- Host Filter: ${vmwareMonitor.resourceFilters.hostName}`);
|
|
2109
2921
|
}
|
|
2110
|
-
if ((
|
|
2922
|
+
if ((_k = vmwareMonitor === null || vmwareMonitor === void 0 ? void 0 : vmwareMonitor.resourceFilters) === null || _k === void 0 ? void 0 : _k.vmName) {
|
|
2111
2923
|
vcenterDetails.push(`- Virtual Machine Filter: ${vmwareMonitor.resourceFilters.vmName}`);
|
|
2112
2924
|
}
|
|
2113
|
-
if ((
|
|
2925
|
+
if ((_l = vmwareMonitor === null || vmwareMonitor === void 0 ? void 0 : vmwareMonitor.resourceFilters) === null || _l === void 0 ? void 0 : _l.datastoreName) {
|
|
2114
2926
|
vcenterDetails.push(`- Datastore Filter: ${vmwareMonitor.resourceFilters.datastoreName}`);
|
|
2115
2927
|
}
|
|
2116
|
-
if ((
|
|
2928
|
+
if ((_m = vmwareMonitor === null || vmwareMonitor === void 0 ? void 0 : vmwareMonitor.resourceFilters) === null || _m === void 0 ? void 0 : _m.resourcePoolPath) {
|
|
2117
2929
|
vcenterDetails.push(`- Resource Pool Filter: ${vmwareMonitor.resourceFilters.resourcePoolPath}`);
|
|
2118
2930
|
}
|
|
2119
2931
|
sections.push(`**vCenter Details**\n${vcenterDetails.join("\n")}`);
|
|
2120
2932
|
}
|
|
2121
2933
|
// Affected resources: a ranked list of object, host and cluster
|
|
2122
2934
|
let renderedBreakdownList = false;
|
|
2123
|
-
|
|
2124
|
-
|
|
2125
|
-
|
|
2126
|
-
|
|
2127
|
-
|
|
2128
|
-
|
|
2129
|
-
|
|
2130
|
-
|
|
2131
|
-
|
|
2132
|
-
|
|
2133
|
-
|
|
2134
|
-
|
|
2135
|
-
|
|
2136
|
-
|
|
2137
|
-
|
|
2138
|
-
|
|
2139
|
-
|
|
2140
|
-
|
|
2141
|
-
})
|
|
2142
|
-
|
|
2143
|
-
|
|
2144
|
-
|
|
2145
|
-
|
|
2146
|
-
|
|
2147
|
-
|
|
2148
|
-
|
|
2149
|
-
|
|
2150
|
-
|
|
2151
|
-
|
|
2152
|
-
|
|
2153
|
-
|
|
2154
|
-
|
|
2155
|
-
|
|
2156
|
-
|
|
2157
|
-
|
|
2158
|
-
|
|
2159
|
-
|
|
2160
|
-
|
|
2161
|
-
|
|
2162
|
-
|
|
2163
|
-
|
|
2164
|
-
|
|
2165
|
-
|
|
2935
|
+
/*
|
|
2936
|
+
* The objects the matched criteria breached, worst first, top 10. For
|
|
2937
|
+
* count metrics filtered to an unhealthy state
|
|
2938
|
+
* (`vcenter.datacenter.host.count{status=red}`) the non-zero rows ARE
|
|
2939
|
+
* the objects with a problem.
|
|
2940
|
+
*/
|
|
2941
|
+
const rows = MonitorCriteriaEvaluator.getPlatformAffectedRows({
|
|
2942
|
+
platform: "vmware",
|
|
2943
|
+
perSeriesMatches: input.perSeriesMatches,
|
|
2944
|
+
namesObject: (identity) => {
|
|
2945
|
+
return Boolean(MonitorCriteriaEvaluator.getVMwareAffectedResourceKind(identity));
|
|
2946
|
+
},
|
|
2947
|
+
metricResponse: metricResponse,
|
|
2948
|
+
monitorStep: input.monitorStep,
|
|
2949
|
+
target: target,
|
|
2950
|
+
breakdown: breakdown,
|
|
2951
|
+
breach: MonitorCriteriaEvaluator.getAffectedResourceBreachPredicate({
|
|
2952
|
+
criteriaInstance: input.criteriaInstance,
|
|
2953
|
+
}),
|
|
2954
|
+
toIdentity: PlatformResourceIdentity.vmware,
|
|
2955
|
+
withContext: PlatformResourceIdentity.withVMwareContext,
|
|
2956
|
+
});
|
|
2957
|
+
/*
|
|
2958
|
+
* Skip the list when no row carries any identity attribute — it
|
|
2959
|
+
* would add nothing. Every vcenter-receiver series carries at
|
|
2960
|
+
* least `vcenter.datacenter.name`, so this only trips on a
|
|
2961
|
+
* breakdown the worker could not attribute at all.
|
|
2962
|
+
*/
|
|
2963
|
+
const hasIdentity = (rows || []).some((row) => {
|
|
2964
|
+
return Boolean(row.seriesLabels ||
|
|
2965
|
+
MonitorCriteriaEvaluator.getVMwareAffectedResourceKind(row.identity));
|
|
2966
|
+
});
|
|
2967
|
+
if (rows && rows.length > 0 && hasIdentity) {
|
|
2968
|
+
sections.push(AffectedResourceList.render({
|
|
2969
|
+
heading: "Affected Resources",
|
|
2970
|
+
overflowNoun: "affected resources",
|
|
2971
|
+
totalCount: rows.length,
|
|
2972
|
+
entries: rows
|
|
2973
|
+
.slice(0, AffectedResourceList.MAX_ENTRIES)
|
|
2974
|
+
.map((row) => {
|
|
2975
|
+
return row.seriesLabels
|
|
2976
|
+
? MonitorCriteriaEvaluator.getSeriesLabelEntry({
|
|
2977
|
+
labels: row.seriesLabels,
|
|
2978
|
+
value: MonitorCriteriaEvaluator.renderAffectedRowValue(row),
|
|
2979
|
+
})
|
|
2980
|
+
: MonitorCriteriaEvaluator.getVMwareAffectedResourceEntry({
|
|
2981
|
+
resource: row.identity,
|
|
2982
|
+
vcenterName: vcenterName,
|
|
2983
|
+
value: MonitorCriteriaEvaluator.renderAffectedRowValue(row),
|
|
2166
2984
|
});
|
|
2167
|
-
|
|
2168
|
-
|
|
2169
|
-
|
|
2170
|
-
}
|
|
2985
|
+
}),
|
|
2986
|
+
}));
|
|
2987
|
+
renderedBreakdownList = true;
|
|
2171
2988
|
}
|
|
2172
2989
|
// Metric results summary (fallback context when no list rendered)
|
|
2173
2990
|
if (!renderedBreakdownList &&
|
|
@@ -2226,87 +3043,103 @@ ${contextBlock}
|
|
|
2226
3043
|
};
|
|
2227
3044
|
}
|
|
2228
3045
|
static buildDockerSwarmRootCauseContext(input) {
|
|
2229
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _j;
|
|
3046
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k;
|
|
2230
3047
|
const metricResponse = input.dataToProcess;
|
|
2231
|
-
const breakdown = metricResponse.dockerSwarmResourceBreakdown;
|
|
2232
|
-
const sections = [];
|
|
2233
3048
|
// Docker Swarm cluster context
|
|
2234
3049
|
const dockerSwarmMonitor = (_a = input.monitorStep.data) === null || _a === void 0 ? void 0 : _a.dockerSwarmMonitor;
|
|
3050
|
+
const target = MonitorCriteriaEvaluator.resolveCriteriaMetricTarget({
|
|
3051
|
+
criteriaInstance: input.criteriaInstance,
|
|
3052
|
+
monitorStep: input.monitorStep,
|
|
3053
|
+
metricResponse: metricResponse,
|
|
3054
|
+
});
|
|
3055
|
+
const breakdown = MonitorCriteriaEvaluator.selectPlatformBreakdown({
|
|
3056
|
+
breakdowns: metricResponse.dockerSwarmResourceBreakdowns,
|
|
3057
|
+
legacyBreakdown: metricResponse.dockerSwarmResourceBreakdown,
|
|
3058
|
+
target: target,
|
|
3059
|
+
});
|
|
3060
|
+
const clusterName = (breakdown === null || breakdown === void 0 ? void 0 : breakdown.clusterName) ||
|
|
3061
|
+
(dockerSwarmMonitor === null || dockerSwarmMonitor === void 0 ? void 0 : dockerSwarmMonitor.clusterIdentifier) ||
|
|
3062
|
+
"Unknown";
|
|
3063
|
+
const sections = [];
|
|
2235
3064
|
if (dockerSwarmMonitor || breakdown) {
|
|
2236
3065
|
const clusterDetails = [];
|
|
2237
|
-
clusterDetails.push(`- Cluster: ${
|
|
2238
|
-
|
|
2239
|
-
|
|
2240
|
-
|
|
2241
|
-
|
|
2242
|
-
((_c = (_b = dockerSwarmMonitor.metricViewConfig) === null || _b === void 0 ? void 0 : _b.queryConfigs) === null || _c === void 0 ? void 0 : _c.
|
|
2243
|
-
|
|
2244
|
-
|
|
2245
|
-
.queryConfigs[0].metricQueryData) === null || _d === void 0 ? void 0 : _d.filterData) === null || _e === void 0 ? void 0 : _e.metricName;
|
|
2246
|
-
if (metricName) {
|
|
2247
|
-
clusterDetails.push(`- Metric: \`${metricName}\``);
|
|
2248
|
-
}
|
|
2249
|
-
}
|
|
2250
|
-
if ((_f = dockerSwarmMonitor === null || dockerSwarmMonitor === void 0 ? void 0 : dockerSwarmMonitor.resourceFilters) === null || _f === void 0 ? void 0 : _f.serviceName) {
|
|
3066
|
+
clusterDetails.push(`- Cluster: ${clusterName}`);
|
|
3067
|
+
clusterDetails.push(...MonitorCriteriaEvaluator.describeCriteriaMetric({
|
|
3068
|
+
platform: "dockerSwarm",
|
|
3069
|
+
target: target,
|
|
3070
|
+
breakdown: breakdown,
|
|
3071
|
+
fallbackMetricName: (_f = (_e = (_d = (_c = (_b = dockerSwarmMonitor === null || dockerSwarmMonitor === void 0 ? void 0 : dockerSwarmMonitor.metricViewConfig) === null || _b === void 0 ? void 0 : _b.queryConfigs) === null || _c === void 0 ? void 0 : _c[0]) === null || _d === void 0 ? void 0 : _d.metricQueryData) === null || _e === void 0 ? void 0 : _e.filterData) === null || _f === void 0 ? void 0 : _f.metricName,
|
|
3072
|
+
}));
|
|
3073
|
+
if ((_g = dockerSwarmMonitor === null || dockerSwarmMonitor === void 0 ? void 0 : dockerSwarmMonitor.resourceFilters) === null || _g === void 0 ? void 0 : _g.serviceName) {
|
|
2251
3074
|
clusterDetails.push(`- Service Filter: ${dockerSwarmMonitor.resourceFilters.serviceName}`);
|
|
2252
3075
|
}
|
|
2253
|
-
if ((
|
|
3076
|
+
if ((_h = dockerSwarmMonitor === null || dockerSwarmMonitor === void 0 ? void 0 : dockerSwarmMonitor.resourceFilters) === null || _h === void 0 ? void 0 : _h.nodeName) {
|
|
2254
3077
|
clusterDetails.push(`- Node Filter: ${dockerSwarmMonitor.resourceFilters.nodeName}`);
|
|
2255
3078
|
}
|
|
2256
|
-
if ((
|
|
3079
|
+
if ((_j = dockerSwarmMonitor === null || dockerSwarmMonitor === void 0 ? void 0 : dockerSwarmMonitor.resourceFilters) === null || _j === void 0 ? void 0 : _j.containerName) {
|
|
2257
3080
|
clusterDetails.push(`- Container Name Filter: ${dockerSwarmMonitor.resourceFilters.containerName}`);
|
|
2258
3081
|
}
|
|
2259
|
-
if ((
|
|
3082
|
+
if ((_k = dockerSwarmMonitor === null || dockerSwarmMonitor === void 0 ? void 0 : dockerSwarmMonitor.resourceFilters) === null || _k === void 0 ? void 0 : _k.containerImage) {
|
|
2260
3083
|
clusterDetails.push(`- Container Image Filter: ${dockerSwarmMonitor.resourceFilters.containerImage}`);
|
|
2261
3084
|
}
|
|
2262
3085
|
sections.push(`**Docker Swarm Cluster Details**\n${clusterDetails.join("\n")}`);
|
|
2263
3086
|
}
|
|
2264
3087
|
// Affected tasks: a ranked list of task, service and node
|
|
2265
3088
|
let renderedBreakdownList = false;
|
|
2266
|
-
|
|
2267
|
-
|
|
2268
|
-
|
|
2269
|
-
|
|
2270
|
-
|
|
2271
|
-
|
|
2272
|
-
|
|
2273
|
-
|
|
2274
|
-
|
|
2275
|
-
|
|
2276
|
-
|
|
2277
|
-
.
|
|
2278
|
-
|
|
2279
|
-
|
|
2280
|
-
|
|
2281
|
-
|
|
2282
|
-
|
|
2283
|
-
|
|
2284
|
-
|
|
2285
|
-
|
|
2286
|
-
|
|
2287
|
-
|
|
2288
|
-
|
|
2289
|
-
|
|
2290
|
-
|
|
2291
|
-
|
|
2292
|
-
|
|
2293
|
-
|
|
2294
|
-
|
|
2295
|
-
|
|
2296
|
-
|
|
2297
|
-
|
|
2298
|
-
|
|
2299
|
-
|
|
2300
|
-
|
|
2301
|
-
|
|
2302
|
-
|
|
2303
|
-
|
|
2304
|
-
|
|
3089
|
+
/*
|
|
3090
|
+
* The tasks the matched criteria breached, worst first, top 10. The
|
|
3091
|
+
* task-down template fires on `container.uptime < 60`, so the worst
|
|
3092
|
+
* task is the one with the LOWEST uptime; the old `> 0`,
|
|
3093
|
+
* highest-first list put the healthiest, longest-running tasks at the
|
|
3094
|
+
* top and pushed the restarting one off the end.
|
|
3095
|
+
*/
|
|
3096
|
+
const rows = MonitorCriteriaEvaluator.getPlatformAffectedRows({
|
|
3097
|
+
platform: "dockerSwarm",
|
|
3098
|
+
perSeriesMatches: input.perSeriesMatches,
|
|
3099
|
+
namesObject: (identity) => {
|
|
3100
|
+
return Boolean(identity.containerName || identity.serviceName || identity.nodeName);
|
|
3101
|
+
},
|
|
3102
|
+
metricResponse: metricResponse,
|
|
3103
|
+
monitorStep: input.monitorStep,
|
|
3104
|
+
target: target,
|
|
3105
|
+
breakdown: breakdown,
|
|
3106
|
+
breach: MonitorCriteriaEvaluator.getAffectedResourceBreachPredicate({
|
|
3107
|
+
criteriaInstance: input.criteriaInstance,
|
|
3108
|
+
}),
|
|
3109
|
+
toIdentity: PlatformResourceIdentity.dockerSwarm,
|
|
3110
|
+
withContext: PlatformResourceIdentity.withDockerSwarmContext,
|
|
3111
|
+
});
|
|
3112
|
+
/*
|
|
3113
|
+
* Skip the list when no row carries any identity label
|
|
3114
|
+
* (cluster-wide series) — it would add nothing.
|
|
3115
|
+
*/
|
|
3116
|
+
const hasIdentity = (rows || []).some((row) => {
|
|
3117
|
+
return Boolean(row.seriesLabels ||
|
|
3118
|
+
row.identity.containerName ||
|
|
3119
|
+
row.identity.serviceName ||
|
|
3120
|
+
row.identity.nodeName);
|
|
3121
|
+
});
|
|
3122
|
+
if (rows && rows.length > 0 && hasIdentity) {
|
|
3123
|
+
sections.push(AffectedResourceList.render({
|
|
3124
|
+
heading: "Affected Tasks",
|
|
3125
|
+
overflowNoun: "affected tasks",
|
|
3126
|
+
totalCount: rows.length,
|
|
3127
|
+
entries: rows
|
|
3128
|
+
.slice(0, AffectedResourceList.MAX_ENTRIES)
|
|
3129
|
+
.map((row) => {
|
|
3130
|
+
return row.seriesLabels
|
|
3131
|
+
? MonitorCriteriaEvaluator.getSeriesLabelEntry({
|
|
3132
|
+
labels: row.seriesLabels,
|
|
3133
|
+
value: MonitorCriteriaEvaluator.renderAffectedRowValue(row),
|
|
3134
|
+
})
|
|
3135
|
+
: MonitorCriteriaEvaluator.getDockerSwarmAffectedResourceEntry({
|
|
3136
|
+
resource: row.identity,
|
|
3137
|
+
clusterName: clusterName,
|
|
3138
|
+
value: MonitorCriteriaEvaluator.renderAffectedRowValue(row),
|
|
2305
3139
|
});
|
|
2306
|
-
|
|
2307
|
-
|
|
2308
|
-
|
|
2309
|
-
}
|
|
3140
|
+
}),
|
|
3141
|
+
}));
|
|
3142
|
+
renderedBreakdownList = true;
|
|
2310
3143
|
}
|
|
2311
3144
|
// Metric results summary (fallback context when no list rendered)
|
|
2312
3145
|
if (!renderedBreakdownList &&
|
|
@@ -2353,40 +3186,114 @@ ${contextBlock}
|
|
|
2353
3186
|
*/
|
|
2354
3187
|
static getAffectedResourceBreachPredicate(input) {
|
|
2355
3188
|
var _a, _b, _c, _d, _e, _f;
|
|
2356
|
-
|
|
2357
|
-
|
|
3189
|
+
/*
|
|
3190
|
+
* Thresholds read exactly as the criteria evaluation reads them. The
|
|
3191
|
+
* dashboard's criteria form saves the threshold as a string ("60"), so
|
|
3192
|
+
* a `typeof === "number"` test dropped every filter a user had edited
|
|
3193
|
+
* and quietly put their criteria back on the `> 0`, highest-first rule.
|
|
3194
|
+
*/
|
|
3195
|
+
const metricFilters = (((_b = (_a = input.criteriaInstance) === null || _a === void 0 ? void 0 : _a.data) === null || _b === void 0 ? void 0 : _b.filters) || [])
|
|
3196
|
+
.filter((f) => {
|
|
3197
|
+
return f.checkOn === CheckOn.MetricValue;
|
|
3198
|
+
})
|
|
3199
|
+
.map((f) => {
|
|
3200
|
+
return {
|
|
3201
|
+
filter: f,
|
|
3202
|
+
threshold: CompareCriteria.convertMetricThresholdToNumber(f.value),
|
|
3203
|
+
};
|
|
3204
|
+
})
|
|
3205
|
+
.filter((f) => {
|
|
3206
|
+
return f.threshold !== null;
|
|
2358
3207
|
});
|
|
2359
3208
|
const opensIncidentOrAlert = ((_d = (_c = input.criteriaInstance) === null || _c === void 0 ? void 0 : _c.data) === null || _d === void 0 ? void 0 : _d.createIncidents) === true ||
|
|
2360
3209
|
((_f = (_e = input.criteriaInstance) === null || _e === void 0 ? void 0 : _e.data) === null || _f === void 0 ? void 0 : _f.createAlerts) === true;
|
|
2361
3210
|
const firesWhenMetricFalls = metricFilters.length > 0 &&
|
|
2362
3211
|
metricFilters.every((f) => {
|
|
2363
|
-
if (f.filterType === FilterType.LessThan ||
|
|
2364
|
-
f.filterType === FilterType.LessThanOrEqualTo) {
|
|
3212
|
+
if (f.filter.filterType === FilterType.LessThan ||
|
|
3213
|
+
f.filter.filterType === FilterType.LessThanOrEqualTo) {
|
|
2365
3214
|
return true;
|
|
2366
3215
|
}
|
|
2367
3216
|
return (input.floorEqualityFiresOnFall === true &&
|
|
2368
3217
|
opensIncidentOrAlert &&
|
|
2369
|
-
f.filterType === FilterType.EqualTo &&
|
|
2370
|
-
f.
|
|
3218
|
+
f.filter.filterType === FilterType.EqualTo &&
|
|
3219
|
+
f.threshold <= 0);
|
|
2371
3220
|
});
|
|
2372
|
-
|
|
3221
|
+
/*
|
|
3222
|
+
* A firing criteria that asks for one exact, non-zero value —
|
|
3223
|
+
* k8s-pod-pending fires on phase `= 1` (Pending) — lists exactly the
|
|
3224
|
+
* rows that were at that value. The `> 0` rule below listed every pod
|
|
3225
|
+
* with a phase, which is all of them, led by the one with the highest
|
|
3226
|
+
* code (Unknown), and sent the reader to `kubectl describe` the wrong
|
|
3227
|
+
* pod.
|
|
3228
|
+
*
|
|
3229
|
+
* A row was at the value if either end of its window was: pod-pending
|
|
3230
|
+
* watches the phase at its Min (a pod that has since started Running
|
|
3231
|
+
* still breached), a memory-pressure `= 1` watches the Max. `= 0` stays
|
|
3232
|
+
* with the floor rule above, which each platform opts into.
|
|
3233
|
+
*/
|
|
3234
|
+
const exactValues = metricFilters.map((f) => {
|
|
3235
|
+
return f.threshold;
|
|
3236
|
+
});
|
|
3237
|
+
const firesOnExactValue = !firesWhenMetricFalls &&
|
|
3238
|
+
opensIncidentOrAlert &&
|
|
3239
|
+
metricFilters.length > 0 &&
|
|
3240
|
+
metricFilters.every((f) => {
|
|
3241
|
+
return f.filter.filterType === FilterType.EqualTo && f.threshold > 0;
|
|
3242
|
+
});
|
|
3243
|
+
if (firesOnExactValue) {
|
|
2373
3244
|
return {
|
|
2374
3245
|
matches: (value) => {
|
|
2375
|
-
return value
|
|
3246
|
+
return exactValues.includes(value);
|
|
2376
3247
|
},
|
|
2377
3248
|
worstIsLowest: false,
|
|
3249
|
+
pickEnd: (ends) => {
|
|
3250
|
+
return exactValues.includes(ends.highest) ? "highest" : "lowest";
|
|
3251
|
+
},
|
|
3252
|
+
};
|
|
3253
|
+
}
|
|
3254
|
+
/*
|
|
3255
|
+
* A criteria that fires when the metric RISES lists the rows past its
|
|
3256
|
+
* threshold. The blanket `> 0` listed every resource with any value at
|
|
3257
|
+
* all — the healthy nodes at 50% under a "> 90%" alert. When no single
|
|
3258
|
+
* row is past it (the criteria compared a sum or an average across
|
|
3259
|
+
* resources) the list still falls back to the non-zero rows.
|
|
3260
|
+
*/
|
|
3261
|
+
const firesWhenMetricRises = metricFilters.length > 0 &&
|
|
3262
|
+
metricFilters.every((f) => {
|
|
3263
|
+
return (f.filter.filterType === FilterType.GreaterThan ||
|
|
3264
|
+
f.filter.filterType === FilterType.GreaterThanOrEqualTo);
|
|
3265
|
+
});
|
|
3266
|
+
const isNonZero = (value) => {
|
|
3267
|
+
return value > 0;
|
|
3268
|
+
};
|
|
3269
|
+
if (firesWhenMetricRises && !firesWhenMetricFalls) {
|
|
3270
|
+
return {
|
|
3271
|
+
matches: (value) => {
|
|
3272
|
+
return metricFilters.some((f) => {
|
|
3273
|
+
return f.filter.filterType === FilterType.GreaterThan
|
|
3274
|
+
? value > f.threshold
|
|
3275
|
+
: value >= f.threshold;
|
|
3276
|
+
});
|
|
3277
|
+
},
|
|
3278
|
+
worstIsLowest: false,
|
|
3279
|
+
fallbackMatches: isNonZero,
|
|
3280
|
+
};
|
|
3281
|
+
}
|
|
3282
|
+
if (!firesWhenMetricFalls) {
|
|
3283
|
+
return {
|
|
3284
|
+
matches: isNonZero,
|
|
3285
|
+
worstIsLowest: false,
|
|
2378
3286
|
};
|
|
2379
3287
|
}
|
|
2380
3288
|
return {
|
|
2381
3289
|
matches: (value) => {
|
|
2382
3290
|
return metricFilters.some((f) => {
|
|
2383
|
-
|
|
2384
|
-
|
|
2385
|
-
return value === threshold;
|
|
3291
|
+
if (f.filter.filterType === FilterType.EqualTo) {
|
|
3292
|
+
return value === f.threshold;
|
|
2386
3293
|
}
|
|
2387
|
-
return f.filterType === FilterType.LessThan
|
|
2388
|
-
? value < threshold
|
|
2389
|
-
: value <= threshold;
|
|
3294
|
+
return f.filter.filterType === FilterType.LessThan
|
|
3295
|
+
? value < f.threshold
|
|
3296
|
+
: value <= f.threshold;
|
|
2390
3297
|
});
|
|
2391
3298
|
},
|
|
2392
3299
|
/*
|
|
@@ -2462,87 +3369,107 @@ ${contextBlock}
|
|
|
2462
3369
|
};
|
|
2463
3370
|
}
|
|
2464
3371
|
static buildCephRootCauseContext(input) {
|
|
2465
|
-
var _a, _b, _c, _d, _e, _f, _g;
|
|
3372
|
+
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
2466
3373
|
const metricResponse = input.dataToProcess;
|
|
2467
|
-
const breakdown = metricResponse.cephResourceBreakdown;
|
|
2468
|
-
const sections = [];
|
|
2469
3374
|
// Ceph cluster context
|
|
2470
3375
|
const cephMonitor = (_a = input.monitorStep.data) === null || _a === void 0 ? void 0 : _a.cephMonitor;
|
|
3376
|
+
const target = MonitorCriteriaEvaluator.resolveCriteriaMetricTarget({
|
|
3377
|
+
criteriaInstance: input.criteriaInstance,
|
|
3378
|
+
monitorStep: input.monitorStep,
|
|
3379
|
+
metricResponse: metricResponse,
|
|
3380
|
+
});
|
|
3381
|
+
const breakdown = MonitorCriteriaEvaluator.selectPlatformBreakdown({
|
|
3382
|
+
breakdowns: metricResponse.cephResourceBreakdowns,
|
|
3383
|
+
legacyBreakdown: metricResponse.cephResourceBreakdown,
|
|
3384
|
+
target: target,
|
|
3385
|
+
});
|
|
3386
|
+
const clusterName = (breakdown === null || breakdown === void 0 ? void 0 : breakdown.clusterName) || (cephMonitor === null || cephMonitor === void 0 ? void 0 : cephMonitor.clusterIdentifier) || "Unknown";
|
|
3387
|
+
const sections = [];
|
|
2471
3388
|
if (cephMonitor || breakdown) {
|
|
2472
3389
|
const clusterDetails = [];
|
|
2473
|
-
clusterDetails.push(`- Cluster: ${
|
|
2474
|
-
|
|
2475
|
-
|
|
2476
|
-
|
|
2477
|
-
|
|
2478
|
-
((_c = (_b = cephMonitor.metricViewConfig) === null || _b === void 0 ? void 0 : _b.queryConfigs) === null || _c === void 0 ? void 0 : _c.
|
|
2479
|
-
|
|
2480
|
-
|
|
2481
|
-
.metricQueryData) === null || _d === void 0 ? void 0 : _d.filterData) === null || _e === void 0 ? void 0 : _e.metricName;
|
|
2482
|
-
if (metricName) {
|
|
2483
|
-
clusterDetails.push(`- Metric: \`${metricName}\``);
|
|
2484
|
-
}
|
|
2485
|
-
}
|
|
2486
|
-
if ((_f = cephMonitor === null || cephMonitor === void 0 ? void 0 : cephMonitor.resourceFilters) === null || _f === void 0 ? void 0 : _f.osdId) {
|
|
3390
|
+
clusterDetails.push(`- Cluster: ${clusterName}`);
|
|
3391
|
+
clusterDetails.push(...MonitorCriteriaEvaluator.describeCriteriaMetric({
|
|
3392
|
+
platform: "ceph",
|
|
3393
|
+
target: target,
|
|
3394
|
+
breakdown: breakdown,
|
|
3395
|
+
fallbackMetricName: (_f = (_e = (_d = (_c = (_b = cephMonitor === null || cephMonitor === void 0 ? void 0 : cephMonitor.metricViewConfig) === null || _b === void 0 ? void 0 : _b.queryConfigs) === null || _c === void 0 ? void 0 : _c[0]) === null || _d === void 0 ? void 0 : _d.metricQueryData) === null || _e === void 0 ? void 0 : _e.filterData) === null || _f === void 0 ? void 0 : _f.metricName,
|
|
3396
|
+
}));
|
|
3397
|
+
if ((_g = cephMonitor === null || cephMonitor === void 0 ? void 0 : cephMonitor.resourceFilters) === null || _g === void 0 ? void 0 : _g.osdId) {
|
|
2487
3398
|
clusterDetails.push(`- OSD Filter: ${cephMonitor.resourceFilters.osdId}`);
|
|
2488
3399
|
}
|
|
2489
|
-
if ((
|
|
3400
|
+
if ((_h = cephMonitor === null || cephMonitor === void 0 ? void 0 : cephMonitor.resourceFilters) === null || _h === void 0 ? void 0 : _h.poolId) {
|
|
2490
3401
|
clusterDetails.push(`- Pool ID Filter: ${cephMonitor.resourceFilters.poolId}`);
|
|
2491
3402
|
}
|
|
2492
3403
|
sections.push(`**Ceph Cluster Details**\n${clusterDetails.join("\n")}`);
|
|
2493
3404
|
}
|
|
2494
3405
|
// Affected resources: a ranked list of daemon, pool and host
|
|
2495
3406
|
let renderedBreakdownList = false;
|
|
2496
|
-
|
|
2497
|
-
|
|
2498
|
-
|
|
2499
|
-
|
|
2500
|
-
|
|
2501
|
-
|
|
2502
|
-
|
|
2503
|
-
|
|
3407
|
+
/*
|
|
3408
|
+
* Keep the rows that satisfy the criteria that just matched, worst
|
|
3409
|
+
* first, top 10 — NOT simply the non-zero rows. For ceph_osd_up /
|
|
3410
|
+
* ceph_osd_in / ceph_mon_quorum_status the criteria is `< 1`, so
|
|
3411
|
+
* the zero rows are the whole point of the incident.
|
|
3412
|
+
*/
|
|
3413
|
+
const rows = MonitorCriteriaEvaluator.getPlatformAffectedRows({
|
|
3414
|
+
platform: "ceph",
|
|
3415
|
+
perSeriesMatches: input.perSeriesMatches,
|
|
3416
|
+
namesObject: (identity) => {
|
|
3417
|
+
return Boolean(identity.daemon ||
|
|
3418
|
+
identity.poolId ||
|
|
3419
|
+
identity.poolName ||
|
|
3420
|
+
identity.hostname);
|
|
3421
|
+
},
|
|
3422
|
+
metricResponse: metricResponse,
|
|
3423
|
+
monitorStep: input.monitorStep,
|
|
3424
|
+
target: target,
|
|
3425
|
+
breakdown: breakdown,
|
|
3426
|
+
breach: MonitorCriteriaEvaluator.getAffectedResourceBreachPredicate({
|
|
2504
3427
|
criteriaInstance: input.criteriaInstance,
|
|
2505
|
-
})
|
|
2506
|
-
|
|
2507
|
-
|
|
2508
|
-
|
|
2509
|
-
|
|
2510
|
-
|
|
2511
|
-
|
|
2512
|
-
|
|
2513
|
-
|
|
2514
|
-
|
|
2515
|
-
|
|
2516
|
-
|
|
2517
|
-
|
|
2518
|
-
|
|
2519
|
-
|
|
2520
|
-
|
|
2521
|
-
|
|
2522
|
-
|
|
2523
|
-
|
|
2524
|
-
|
|
2525
|
-
|
|
2526
|
-
|
|
2527
|
-
|
|
2528
|
-
|
|
2529
|
-
|
|
2530
|
-
|
|
2531
|
-
|
|
2532
|
-
|
|
2533
|
-
|
|
2534
|
-
|
|
2535
|
-
|
|
2536
|
-
|
|
2537
|
-
|
|
2538
|
-
|
|
2539
|
-
|
|
2540
|
-
|
|
3428
|
+
}),
|
|
3429
|
+
toIdentity: PlatformResourceIdentity.ceph,
|
|
3430
|
+
withContext: PlatformResourceIdentity.withCephContext,
|
|
3431
|
+
});
|
|
3432
|
+
/*
|
|
3433
|
+
* Skip the list when no row carries any identity label
|
|
3434
|
+
* (cluster-wide series like ceph_health_status) — it would add
|
|
3435
|
+
* nothing.
|
|
3436
|
+
*/
|
|
3437
|
+
const hasIdentity = (rows || []).some((row) => {
|
|
3438
|
+
return Boolean(row.seriesLabels ||
|
|
3439
|
+
row.identity.daemon ||
|
|
3440
|
+
row.identity.poolId ||
|
|
3441
|
+
row.identity.poolName ||
|
|
3442
|
+
row.identity.hostname);
|
|
3443
|
+
});
|
|
3444
|
+
/*
|
|
3445
|
+
* Which metric the rows are about, for the entry's "Health Check"
|
|
3446
|
+
* titling: the criteria's own query, else the breakdown's.
|
|
3447
|
+
*/
|
|
3448
|
+
const rowsMetricName = MonitorCriteriaEvaluator.getAnalysisMetricName(target) ||
|
|
3449
|
+
(breakdown === null || breakdown === void 0 ? void 0 : breakdown.metricName) ||
|
|
3450
|
+
"";
|
|
3451
|
+
if (rows && rows.length > 0 && hasIdentity) {
|
|
3452
|
+
sections.push(AffectedResourceList.render({
|
|
3453
|
+
heading: "Affected Resources",
|
|
3454
|
+
overflowNoun: "affected resources",
|
|
3455
|
+
totalCount: rows.length,
|
|
3456
|
+
entries: rows
|
|
3457
|
+
.slice(0, AffectedResourceList.MAX_ENTRIES)
|
|
3458
|
+
.map((row) => {
|
|
3459
|
+
return row.seriesLabels
|
|
3460
|
+
? MonitorCriteriaEvaluator.getSeriesLabelEntry({
|
|
3461
|
+
labels: row.seriesLabels,
|
|
3462
|
+
value: MonitorCriteriaEvaluator.renderAffectedRowValue(row),
|
|
3463
|
+
})
|
|
3464
|
+
: MonitorCriteriaEvaluator.getCephAffectedResourceEntry({
|
|
3465
|
+
resource: row.identity,
|
|
3466
|
+
clusterName: clusterName,
|
|
3467
|
+
metricName: rowsMetricName,
|
|
3468
|
+
value: MonitorCriteriaEvaluator.renderAffectedRowValue(row),
|
|
2541
3469
|
});
|
|
2542
|
-
|
|
2543
|
-
|
|
2544
|
-
|
|
2545
|
-
}
|
|
3470
|
+
}),
|
|
3471
|
+
}));
|
|
3472
|
+
renderedBreakdownList = true;
|
|
2546
3473
|
}
|
|
2547
3474
|
// Metric results summary (fallback context when no list rendered)
|
|
2548
3475
|
if (!renderedBreakdownList &&
|
|
@@ -2576,14 +3503,13 @@ ${contextBlock}
|
|
|
2576
3503
|
* kubeletstats cores gauge that four other places in this repo warn
|
|
2577
3504
|
* is misnamed, so 1.4 cores in use read as "1.4% CPU utilization".
|
|
2578
3505
|
*/
|
|
2579
|
-
const topResourceValue =
|
|
2580
|
-
|
|
2581
|
-
unit: MonitorCriteriaEvaluator.getPlatformMetricUnit({
|
|
3506
|
+
const topResourceValue = input.topResourceValue ||
|
|
3507
|
+
MonitorCriteriaEvaluator.formatPlatformMetricValue({
|
|
2582
3508
|
platform: "kubernetes",
|
|
2583
3509
|
metricName: metricName,
|
|
2584
|
-
|
|
2585
|
-
|
|
2586
|
-
|
|
3510
|
+
metricUnit: breakdown.metricUnit,
|
|
3511
|
+
value: topResource.metricValue,
|
|
3512
|
+
});
|
|
2587
3513
|
if (metricName === "k8s.container.restarts" ||
|
|
2588
3514
|
metricName.includes("restart")) {
|
|
2589
3515
|
lines.push(`Container restart count is elevated, indicating a potential CrashLoopBackOff condition.`);
|
|
@@ -2620,6 +3546,12 @@ ${contextBlock}
|
|
|
2620
3546
|
lines.push(`Recommended actions: Check node conditions with \`kubectl describe node ${topResource.nodeName || "<node-name>"}\` and verify kubelet status on the node.`);
|
|
2621
3547
|
}
|
|
2622
3548
|
else if (metricName === "k8s.node.cpu.utilization" ||
|
|
3549
|
+
/*
|
|
3550
|
+
* The numerator of the "High Node CPU Utilization" ratio template
|
|
3551
|
+
* (k8s.node.cpu.usage ÷ k8s.node.allocatable_cpu × 100), which is
|
|
3552
|
+
* what a formula criteria is analysed as.
|
|
3553
|
+
*/
|
|
3554
|
+
metricName === "k8s.node.cpu.usage" ||
|
|
2623
3555
|
/*
|
|
2624
3556
|
* Node-scoped ONLY. The bare substring test used to swallow every
|
|
2625
3557
|
* pod- and container-scoped CPU metric — `k8s.pod.cpu.utilization`,
|
|
@@ -2651,8 +3583,16 @@ ${contextBlock}
|
|
|
2651
3583
|
lines.push(`Common causes: memory leaks in applications, insufficient memory limits on pods, too many pods scheduled on the node, or growing dataset sizes.`);
|
|
2652
3584
|
lines.push(`Recommended actions: Check memory consumers with \`kubectl top pods --all-namespaces --sort-by=memory\` and review pod memory limits. Consider scaling the cluster or adding nodes with more memory.`);
|
|
2653
3585
|
}
|
|
2654
|
-
else if (
|
|
2655
|
-
|
|
3586
|
+
else if (
|
|
3587
|
+
/*
|
|
3588
|
+
* The k8s_cluster receiver has no unavailable-replicas series. The
|
|
3589
|
+
* replica-mismatch template is a formula (`desired - available`),
|
|
3590
|
+
* analysed as its first operand, k8s.deployment.desired, so it lands
|
|
3591
|
+
* in the generic branch below, which names the formula. What still
|
|
3592
|
+
* reaches this one is a custom monitor on an "unavailable" series
|
|
3593
|
+
* such as kube-state-metrics' `kube_deployment_status_replicas_unavailable`.
|
|
3594
|
+
*/
|
|
3595
|
+
metricName.includes("unavailable")) {
|
|
2656
3596
|
lines.push(`Deployment has unavailable replicas, indicating a mismatch between desired and available replicas.`);
|
|
2657
3597
|
if (topResource.workloadName) {
|
|
2658
3598
|
lines.push(`${topResource.workloadType || "Deployment"} \`${topResource.workloadName}\` has **${topResourceValue}** unavailable replica(s).`);
|
|
@@ -2689,13 +3629,38 @@ ${contextBlock}
|
|
|
2689
3629
|
lines.push(`Recommended actions: Check DaemonSet status with \`kubectl describe daemonset ${topResource.workloadName || "<daemonset>"}\` and verify node labels and taints.`);
|
|
2690
3630
|
}
|
|
2691
3631
|
else {
|
|
2692
|
-
|
|
2693
|
-
|
|
3632
|
+
/*
|
|
3633
|
+
* Generic Kubernetes context. It names what the criteria compared —
|
|
3634
|
+
* a formula by its legend and expression, since the metric the
|
|
3635
|
+
* branches above key on is only its numerator — and the worst
|
|
3636
|
+
* resource's value, so the reader does not have to find it in the
|
|
3637
|
+
* list above.
|
|
3638
|
+
*/
|
|
3639
|
+
const target = input.target;
|
|
3640
|
+
if (target === null || target === void 0 ? void 0 : target.isFormula) {
|
|
3641
|
+
const formulaName = target.displayName || `\`${target.alias}\``;
|
|
3642
|
+
const expression = target.formulaExpression
|
|
3643
|
+
? ` (\`${target.formulaExpression}\`)`
|
|
3644
|
+
: "";
|
|
3645
|
+
lines.push(`${formulaName}${expression} has breached the configured threshold.`);
|
|
3646
|
+
}
|
|
3647
|
+
else {
|
|
3648
|
+
const friendlyName = breakdown.metricFriendlyName &&
|
|
3649
|
+
breakdown.metricFriendlyName !== metricName
|
|
3650
|
+
? ` (${breakdown.metricFriendlyName})`
|
|
3651
|
+
: "";
|
|
3652
|
+
lines.push(`Kubernetes metric \`${metricName}\`${friendlyName} has breached the configured threshold.`);
|
|
3653
|
+
}
|
|
2694
3654
|
if (topResource.podName) {
|
|
2695
|
-
lines.push(`Most affected pod: \`${topResource.podName}
|
|
3655
|
+
lines.push(`Most affected pod: \`${topResource.podName}\` (**${topResourceValue}**)`);
|
|
3656
|
+
}
|
|
3657
|
+
else if (topResource.workloadName) {
|
|
3658
|
+
lines.push(`Most affected ${topResource.workloadType || "workload"}: \`${topResource.workloadName}\` (**${topResourceValue}**)`);
|
|
2696
3659
|
}
|
|
2697
3660
|
if (topResource.nodeName) {
|
|
2698
|
-
lines.push(
|
|
3661
|
+
lines.push(topResource.podName
|
|
3662
|
+
? `Most affected node: \`${topResource.nodeName}\``
|
|
3663
|
+
: `Most affected node: \`${topResource.nodeName}\` (**${topResourceValue}**)`);
|
|
2699
3664
|
}
|
|
2700
3665
|
lines.push(`Recommended actions: Investigate the affected resources using \`kubectl describe\` and \`kubectl logs\` commands.`);
|
|
2701
3666
|
}
|