@oneuptime/common 14.0.0 → 14.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Models/DatabaseModels/Index.ts +4 -0
- package/Models/DatabaseModels/ServiceLevelObjectiveFeed.ts +2 -0
- package/Models/DatabaseModels/ServiceLevelObjectiveLabelRule.ts +522 -0
- package/Models/DatabaseModels/ServiceLevelObjectiveMonitorRule.ts +38 -4
- package/Models/DatabaseModels/ServiceLevelObjectiveOwnerRule.ts +603 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1794100000000-AddSloLabelAndOwnerRules.ts +248 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1794200000000-AddSloMonitorRuleMonitorType.ts +19 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +4 -0
- package/Server/Services/DatabaseService.ts +10 -0
- package/Server/Services/Index.ts +4 -0
- package/Server/Services/MonitorService.ts +3 -2
- package/Server/Services/ServiceLevelObjectiveLabelRuleEngineService.ts +385 -0
- package/Server/Services/ServiceLevelObjectiveLabelRuleService.ts +51 -0
- package/Server/Services/ServiceLevelObjectiveMonitorRuleEngineService.ts +92 -16
- package/Server/Services/ServiceLevelObjectiveMonitorRuleService.ts +36 -1
- package/Server/Services/ServiceLevelObjectiveOwnerRuleEngineService.ts +521 -0
- package/Server/Services/ServiceLevelObjectiveOwnerRuleService.ts +51 -0
- package/Server/Services/ServiceLevelObjectiveService.ts +28 -0
- package/Server/Types/Workflow/Components/Telegram/SendMessageToChat.ts +27 -1
- package/Server/Utils/AI/Toolbox/SloTools.ts +1 -0
- package/Server/Utils/Monitor/AffectedResourceList.ts +31 -73
- package/Server/Utils/Monitor/Criteria/CompareCriteria.ts +1 -1
- package/Server/Utils/Monitor/Criteria/MetricMonitorCriteria.ts +1 -1
- package/Server/Utils/Monitor/MonitorCriteriaEvaluator.ts +181 -136
- package/Server/Utils/Monitor/RootCauseList.ts +139 -0
- package/Server/Utils/Rules/RuleRun/RuleRunRegistry.ts +28 -0
- package/Server/Utils/Slo/SloRulePatternValidator.ts +42 -0
- package/Tests/App/Dashboard/FeedFilterSortIntegration.test.tsx +1632 -0
- package/Tests/App/Dashboard/FeedOptionsLocales.test.ts +250 -0
- package/Tests/App/Dashboard/FeedOrdering.test.ts +279 -9
- package/Tests/App/Dashboard/InvestigationFeedRefresh.test.tsx +60 -1
- package/Tests/App/Dashboard/InvestigationPanel.test.tsx +594 -3
- package/Tests/App/Dashboard/ProductOrientation.test.tsx +646 -0
- package/Tests/App/Dashboard/ResourceFeed.test.tsx +612 -2
- package/Tests/App/Dashboard/ResourceFeedPageWiring.test.ts +30 -0
- package/Tests/App/Dashboard/ResourceFeedPagesFilterSort.test.tsx +1202 -0
- package/Tests/App/Dashboard/ScheduledMaintenanceFeedRefresh.test.tsx +52 -1
- package/Tests/App/Dashboard/SloFeed.test.tsx +106 -1
- package/Tests/App/Dashboard/SloMonitorRuleCriteria.test.tsx +566 -0
- package/Tests/App/Dashboard/SloNavigationWiring.test.tsx +6 -4
- package/Tests/App/Dashboard/SloNoticeBanner.test.tsx +186 -0
- package/Tests/App/Dashboard/SloOverviewKpiStrip.test.tsx +388 -44
- package/Tests/App/Dashboard/SloOverviewLayout.test.tsx +613 -0
- package/Tests/Models/DatabaseModels/ResourceFeedModels.test.ts +0 -8
- package/Tests/Models/DatabaseModels/SloLabelAndOwnerRuleModels.test.ts +404 -0
- package/Tests/Models/DatabaseModels/SloOverhaulModels.test.ts +17 -1
- package/Tests/Models/DatabaseModels/StaticRuleCriteriaInheritance.test.ts +4 -2
- package/Tests/Server/Infrastructure/Postgres/AddConfigurableRuleCriteriaMigration.test.ts +3 -0
- package/Tests/Server/Infrastructure/Postgres/AddSloLabelAndOwnerRulesMigration.test.ts +407 -0
- package/Tests/Server/Infrastructure/Postgres/AddSloMonitorRuleMonitorTypeMigration.test.ts +171 -0
- package/Tests/Server/Infrastructure/Postgres/SloProductOverhaulMigration.test.ts +88 -4
- package/Tests/Server/Services/DatabaseServiceRuleCriteriaValidation.test.ts +104 -0
- package/Tests/Server/Services/RuleRun/LabelRuleEnginesGroupBRun.test.ts +48 -1
- package/Tests/Server/Services/RuleRun/OwnerRuleEnginesGroupBRun.test.ts +30 -0
- package/Tests/Server/Services/ServiceLevelObjectiveLabelAndOwnerRuleEngines.test.ts +1170 -0
- package/Tests/Server/Services/ServiceLevelObjectiveLabelAndOwnerRuleServices.test.ts +172 -0
- package/Tests/Server/Services/ServiceLevelObjectiveMonitorRuleEngineService.test.ts +323 -0
- package/Tests/Server/Services/ServiceLevelObjectiveMonitorRuleService.test.ts +115 -0
- package/Tests/Server/Services/ServiceLevelObjectiveMonitorRuleTriggers.test.ts +21 -2
- package/Tests/Server/Services/ServiceLevelObjectiveMonitorTypePostgres.test.ts +480 -0
- package/Tests/Server/Services/ServiceLevelObjectiveService.test.ts +162 -0
- package/Tests/Server/Services/StaticRuleCriteriaRuntimeCoverage.test.ts +45 -6
- package/Tests/Server/Types/Database/FeedEventTypeFilterQuery.test.ts +745 -0
- package/Tests/Server/Types/Markdown.test.ts +2 -1
- package/Tests/Server/Types/Workflow/Components/ApiComponentSsrf.test.ts +49 -0
- package/Tests/Server/Types/Workflow/Components/TelegramSendMessageToChat.test.ts +331 -0
- package/Tests/Server/Utils/AI/SloTools.test.ts +10 -0
- package/Tests/Server/Utils/Monitor/Criteria/MetricMonitorCriteriaAnomalyUnits.test.ts +1 -1
- package/Tests/Server/Utils/Monitor/MonitorCriteriaEvaluator.test.ts +405 -0
- package/Tests/Server/Utils/Monitor/MonitorCriteriaEvaluatorBreachingSamples.test.ts +1101 -0
- package/Tests/Server/Utils/Monitor/MonitorCriteriaEvaluatorMetricUnits.test.ts +106 -80
- package/Tests/Server/Utils/Monitor/RootCauseList.test.ts +252 -0
- package/Tests/Server/Utils/Rules/RuleRun/RuleRunPermission.test.ts +154 -0
- package/Tests/Server/Utils/SSRFProtection.test.ts +111 -0
- package/Tests/Server/Utils/Slo/SloRulePatternValidator.test.ts +67 -0
- package/Tests/Server/Utils/VM/VMRunnerSsrf.test.ts +213 -0
- package/Tests/Types/API/Route.test.ts +56 -0
- package/Tests/Types/API/URLSchemeLikePath.test.ts +304 -0
- package/Tests/UI/Components/FeedOptions.test.ts +1404 -0
- package/Tests/UI/Components/FeedOptionsButton.test.tsx +2603 -0
- package/Tests/UI/Components/Icon.test.tsx +26 -0
- package/Tests/UI/Components/RuleCriteria/RuleCriteriaModelTable.test.tsx +3 -3
- package/Tests/UI/Components/useFeedItemsViewKey.test.tsx +1017 -0
- package/Tests/UI/Components/useFeedOptions.test.tsx +1107 -0
- package/Tests/Utils/LabelRuleImportExport.test.ts +102 -0
- package/Tests/Utils/Slo/SloDuration.test.ts +115 -24
- package/Tests/Utils/Slo/SloHealth.test.ts +93 -10
- package/Tests/Utils/Slo/SloMonitorRuleCriteria.test.ts +109 -0
- package/Tests/Utils/Slo/SloOverviewText.test.ts +64 -0
- package/Types/API/Route.ts +19 -2
- package/Types/API/URL.ts +26 -2
- package/Types/Monitor/MetricMonitor/MetricCriteriaContext.ts +6 -5
- package/Types/Monitor/MetricMonitor/MetricMonitorResponse.ts +9 -0
- package/Types/Permission.ts +90 -0
- package/Types/Rules/RuleCriteriaFieldRegistry.ts +11 -0
- package/Types/Rules/RuleRun.ts +4 -0
- package/UI/Components/Feed/FeedOptions.ts +427 -0
- package/UI/Components/Feed/FeedOptionsButton.tsx +692 -0
- package/UI/Components/Feed/useFeedItems.ts +28 -9
- package/UI/Components/Feed/useFeedOptions.ts +225 -0
- package/UI/Components/Icon/Icon.tsx +1 -1
- package/Utils/LabelRuleImportExport.ts +27 -9
- package/Utils/Monitor/MetricValueFormatter.ts +2 -2
- package/Utils/Rules/MonitorTypeRuleCriteria.ts +31 -0
- package/Utils/Slo/SloDuration.ts +22 -6
- package/Utils/Slo/SloHealth.ts +8 -7
- package/Utils/Slo/SloMonitorRuleCriteria.ts +33 -1
- package/Utils/Slo/SloOverviewText.ts +33 -0
- package/Utils/Slo/SloProjection.ts +4 -3
- package/build/dist/Models/DatabaseModels/Index.js +4 -0
- package/build/dist/Models/DatabaseModels/Index.js.map +1 -1
- package/build/dist/Models/DatabaseModels/ServiceLevelObjectiveFeed.js +2 -0
- package/build/dist/Models/DatabaseModels/ServiceLevelObjectiveFeed.js.map +1 -1
- package/build/dist/Models/DatabaseModels/ServiceLevelObjectiveLabelRule.js +530 -0
- package/build/dist/Models/DatabaseModels/ServiceLevelObjectiveLabelRule.js.map +1 -0
- package/build/dist/Models/DatabaseModels/ServiceLevelObjectiveMonitorRule.js +39 -4
- package/build/dist/Models/DatabaseModels/ServiceLevelObjectiveMonitorRule.js.map +1 -1
- package/build/dist/Models/DatabaseModels/ServiceLevelObjectiveOwnerRule.js +612 -0
- package/build/dist/Models/DatabaseModels/ServiceLevelObjectiveOwnerRule.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1794100000000-AddSloLabelAndOwnerRules.js +93 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1794100000000-AddSloLabelAndOwnerRules.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1794200000000-AddSloMonitorRuleMonitorType.js +12 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1794200000000-AddSloMonitorRuleMonitorType.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/Services/DatabaseService.js +7 -0
- package/build/dist/Server/Services/DatabaseService.js.map +1 -1
- package/build/dist/Server/Services/Index.js +4 -0
- package/build/dist/Server/Services/Index.js.map +1 -1
- package/build/dist/Server/Services/MonitorService.js +3 -2
- package/build/dist/Server/Services/MonitorService.js.map +1 -1
- package/build/dist/Server/Services/ServiceLevelObjectiveLabelRuleEngineService.js +295 -0
- package/build/dist/Server/Services/ServiceLevelObjectiveLabelRuleEngineService.js.map +1 -0
- package/build/dist/Server/Services/ServiceLevelObjectiveLabelRuleService.js +56 -0
- package/build/dist/Server/Services/ServiceLevelObjectiveLabelRuleService.js.map +1 -0
- package/build/dist/Server/Services/ServiceLevelObjectiveMonitorRuleEngineService.js +59 -14
- package/build/dist/Server/Services/ServiceLevelObjectiveMonitorRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/ServiceLevelObjectiveMonitorRuleService.js +22 -1
- package/build/dist/Server/Services/ServiceLevelObjectiveMonitorRuleService.js.map +1 -1
- package/build/dist/Server/Services/ServiceLevelObjectiveOwnerRuleEngineService.js +400 -0
- package/build/dist/Server/Services/ServiceLevelObjectiveOwnerRuleEngineService.js.map +1 -0
- package/build/dist/Server/Services/ServiceLevelObjectiveOwnerRuleService.js +56 -0
- package/build/dist/Server/Services/ServiceLevelObjectiveOwnerRuleService.js.map +1 -0
- package/build/dist/Server/Services/ServiceLevelObjectiveService.js +21 -0
- package/build/dist/Server/Services/ServiceLevelObjectiveService.js.map +1 -1
- package/build/dist/Server/Types/Workflow/Components/Telegram/SendMessageToChat.js +20 -1
- package/build/dist/Server/Types/Workflow/Components/Telegram/SendMessageToChat.js.map +1 -1
- package/build/dist/Server/Utils/AI/Toolbox/SloTools.js +1 -0
- package/build/dist/Server/Utils/AI/Toolbox/SloTools.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/AffectedResourceList.js +22 -51
- package/build/dist/Server/Utils/Monitor/AffectedResourceList.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/Criteria/CompareCriteria.js +1 -1
- package/build/dist/Server/Utils/Monitor/Criteria/MetricMonitorCriteria.js +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorCriteriaEvaluator.js +139 -109
- package/build/dist/Server/Utils/Monitor/MonitorCriteriaEvaluator.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/RootCauseList.js +101 -0
- package/build/dist/Server/Utils/Monitor/RootCauseList.js.map +1 -0
- package/build/dist/Server/Utils/Rules/RuleRun/RuleRunRegistry.js +28 -0
- package/build/dist/Server/Utils/Rules/RuleRun/RuleRunRegistry.js.map +1 -1
- package/build/dist/Server/Utils/Slo/SloRulePatternValidator.js +28 -0
- package/build/dist/Server/Utils/Slo/SloRulePatternValidator.js.map +1 -0
- package/build/dist/Types/API/Route.js +18 -2
- package/build/dist/Types/API/Route.js.map +1 -1
- package/build/dist/Types/API/URL.js +23 -2
- package/build/dist/Types/API/URL.js.map +1 -1
- package/build/dist/Types/Permission.js +84 -0
- package/build/dist/Types/Permission.js.map +1 -1
- package/build/dist/Types/Rules/RuleCriteriaFieldRegistry.js +11 -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/UI/Components/Feed/FeedOptions.js +235 -0
- package/build/dist/UI/Components/Feed/FeedOptions.js.map +1 -0
- package/build/dist/UI/Components/Feed/FeedOptionsButton.js +346 -0
- package/build/dist/UI/Components/Feed/FeedOptionsButton.js.map +1 -0
- package/build/dist/UI/Components/Feed/useFeedItems.js +17 -7
- package/build/dist/UI/Components/Feed/useFeedItems.js.map +1 -1
- package/build/dist/UI/Components/Feed/useFeedOptions.js +130 -0
- package/build/dist/UI/Components/Feed/useFeedOptions.js.map +1 -0
- package/build/dist/UI/Components/Icon/Icon.js +1 -1
- package/build/dist/UI/Components/Icon/Icon.js.map +1 -1
- package/build/dist/Utils/LabelRuleImportExport.js +22 -6
- package/build/dist/Utils/LabelRuleImportExport.js.map +1 -1
- package/build/dist/Utils/Monitor/MetricValueFormatter.js +2 -2
- package/build/dist/Utils/Rules/MonitorTypeRuleCriteria.js +18 -0
- package/build/dist/Utils/Rules/MonitorTypeRuleCriteria.js.map +1 -0
- package/build/dist/Utils/Slo/SloDuration.js +13 -5
- package/build/dist/Utils/Slo/SloDuration.js.map +1 -1
- package/build/dist/Utils/Slo/SloHealth.js +8 -7
- package/build/dist/Utils/Slo/SloHealth.js.map +1 -1
- package/build/dist/Utils/Slo/SloMonitorRuleCriteria.js +16 -1
- package/build/dist/Utils/Slo/SloMonitorRuleCriteria.js.map +1 -1
- package/build/dist/Utils/Slo/SloOverviewText.js +16 -0
- package/build/dist/Utils/Slo/SloOverviewText.js.map +1 -1
- package/build/dist/Utils/Slo/SloProjection.js.map +1 -1
- package/package.json +1 -1
|
@@ -1,4 +1,8 @@
|
|
|
1
1
|
import { escapeMarkdownInline } from "../../../Utils/Markdown/MarkdownEscape";
|
|
2
|
+
import RootCauseList, {
|
|
3
|
+
RootCauseListDetail,
|
|
4
|
+
RootCauseListItem,
|
|
5
|
+
} from "./RootCauseList";
|
|
2
6
|
|
|
3
7
|
/*
|
|
4
8
|
* The "Affected Resources" block of a platform monitor's root cause.
|
|
@@ -30,10 +34,8 @@ import { escapeMarkdownInline } from "../../../Utils/Markdown/MarkdownEscape";
|
|
|
30
34
|
* and the rest of its identity sits underneath as labelled bullets. A
|
|
31
35
|
* missing attribute is simply left out, where the table had to print "-".
|
|
32
36
|
*
|
|
33
|
-
*
|
|
34
|
-
*
|
|
35
|
-
* Markdown.convertToPlainText all understand a nested list, so nothing
|
|
36
|
-
* downstream needs to know this block exists.
|
|
37
|
+
* The list itself is a RootCauseList, the shape the Breaching Samples block
|
|
38
|
+
* of a metric monitor's root cause uses too.
|
|
37
39
|
*/
|
|
38
40
|
|
|
39
41
|
export interface AffectedResourceListDetail {
|
|
@@ -67,46 +69,36 @@ export default class AffectedResourceList {
|
|
|
67
69
|
// The resources to show, already sorted worst first.
|
|
68
70
|
entries: Array<AffectedResourceListEntry>;
|
|
69
71
|
}): string {
|
|
70
|
-
const
|
|
71
|
-
|
|
72
|
-
input.entries.forEach(
|
|
73
|
-
(entry: AffectedResourceListEntry, index: number): void => {
|
|
74
|
-
const marker: string = `${index + 1}.`;
|
|
75
|
-
|
|
76
|
-
/*
|
|
77
|
-
* A nested bullet belongs to its item only when it is indented to
|
|
78
|
-
* the item's content column, which is one past the marker — three
|
|
79
|
-
* spaces under "1.", four under "10.". A fixed three-space indent
|
|
80
|
-
* would push item 10's details out into a separate top-level list.
|
|
81
|
-
*/
|
|
82
|
-
const indent: string = " ".repeat(marker.length + 1);
|
|
83
|
-
|
|
72
|
+
const items: Array<RootCauseListItem> = input.entries.map(
|
|
73
|
+
(entry: AffectedResourceListEntry): RootCauseListItem => {
|
|
84
74
|
/*
|
|
85
75
|
* The kind is bold so each item's first line stands out from the
|
|
86
76
|
* detail bullets under it — the value at the end of the line is
|
|
87
77
|
* bold too, so the eye lands on what it is and how bad it is.
|
|
88
78
|
*/
|
|
89
79
|
const kind: string = escapeMarkdownInline(entry.kind).trim();
|
|
90
|
-
const title: string = [kind ? `**${kind}**` : "", entry.name.trim()]
|
|
91
|
-
.filter((part: string): boolean => {
|
|
92
|
-
return part.length > 0;
|
|
93
|
-
})
|
|
94
|
-
.join(" ");
|
|
95
80
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
81
|
+
return {
|
|
82
|
+
title: [kind ? `**${kind}**` : "", entry.name.trim()]
|
|
83
|
+
.filter((part: string): boolean => {
|
|
84
|
+
return part.length > 0;
|
|
85
|
+
})
|
|
86
|
+
.join(" "),
|
|
87
|
+
value: entry.value,
|
|
88
|
+
details: entry.details.map(
|
|
89
|
+
(detail: AffectedResourceListDetail): RootCauseListDetail => {
|
|
90
|
+
return {
|
|
91
|
+
label: escapeMarkdownInline(detail.label),
|
|
92
|
+
value: detail.value,
|
|
93
|
+
};
|
|
94
|
+
},
|
|
95
|
+
),
|
|
96
|
+
};
|
|
107
97
|
},
|
|
108
98
|
);
|
|
109
99
|
|
|
100
|
+
const lines: Array<string> = [RootCauseList.render(items)];
|
|
101
|
+
|
|
110
102
|
const hiddenCount: number = input.totalCount - input.entries.length;
|
|
111
103
|
|
|
112
104
|
if (hiddenCount > 0) {
|
|
@@ -125,47 +117,13 @@ export default class AffectedResourceList {
|
|
|
125
117
|
}
|
|
126
118
|
|
|
127
119
|
/*
|
|
128
|
-
* A resource identifier as an inline code span.
|
|
129
|
-
*
|
|
130
|
-
*
|
|
131
|
-
*
|
|
132
|
-
* backtick in single backticks closes the span early and spills the rest
|
|
133
|
-
* of the name — and whatever markdown it contains — into the list. So the
|
|
134
|
-
* fence is always one backtick longer than the longest run inside the
|
|
135
|
-
* value, and padded with a space on each side when the value has any
|
|
136
|
-
* backticks at all (CommonMark strips exactly one from each side, so the
|
|
137
|
-
* padding never shows). Line breaks become spaces: a newline inside a
|
|
138
|
-
* list item would end the item.
|
|
120
|
+
* A resource identifier as an inline code span. The identifiers come from
|
|
121
|
+
* telemetry attributes, and a VMware VM or a Proxmox guest can be named
|
|
122
|
+
* anything — RootCauseList.code keeps a name with backticks or line breaks
|
|
123
|
+
* inside its span.
|
|
139
124
|
*/
|
|
140
125
|
public static code(value: string | undefined | null): string {
|
|
141
|
-
|
|
142
|
-
return "";
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
const text: string = String(value)
|
|
146
|
-
.replace(/\s*[\r\n]+\s*/g, " ")
|
|
147
|
-
.trim();
|
|
148
|
-
|
|
149
|
-
if (text.length === 0) {
|
|
150
|
-
return "";
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
const backtickRuns: Array<string> = text.match(/`+/g) || [];
|
|
154
|
-
|
|
155
|
-
const longestRun: number = backtickRuns.reduce(
|
|
156
|
-
(longest: number, run: string): number => {
|
|
157
|
-
return Math.max(longest, run.length);
|
|
158
|
-
},
|
|
159
|
-
0,
|
|
160
|
-
);
|
|
161
|
-
|
|
162
|
-
if (longestRun === 0) {
|
|
163
|
-
return `\`${text}\``;
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
const fence: string = "`".repeat(longestRun + 1);
|
|
167
|
-
|
|
168
|
-
return `${fence} ${text} ${fence}`;
|
|
126
|
+
return RootCauseList.code(value);
|
|
169
127
|
}
|
|
170
128
|
|
|
171
129
|
/*
|
|
@@ -984,7 +984,7 @@ export default class CompareCriteria {
|
|
|
984
984
|
* reads naturally ("is 42, 55, 60"). For larger arrays, summarize
|
|
985
985
|
* — dumping 30+ numbers on one line makes the root cause unreadable
|
|
986
986
|
* and the detailed breakdown is shown in the Breaching Samples
|
|
987
|
-
*
|
|
987
|
+
* list below.
|
|
988
988
|
*/
|
|
989
989
|
const MAX_INLINE: number = 5;
|
|
990
990
|
|
|
@@ -1004,7 +1004,7 @@ export default class MetricMonitorCriteria {
|
|
|
1004
1004
|
const sigmaAbs: number = Math.abs(firstBreach.sigma);
|
|
1005
1005
|
|
|
1006
1006
|
/*
|
|
1007
|
-
* Same rendering as the breaching-samples
|
|
1007
|
+
* Same rendering as the breaching-samples list and the comparison
|
|
1008
1008
|
* sentence — an anomaly on a memory metric reads "1.07 GB", not
|
|
1009
1009
|
* "1073741824.000 By". σ is a count of standard deviations, not a
|
|
1010
1010
|
* quantity in the metric's unit, so it stays a bare number; the
|
|
@@ -34,6 +34,10 @@ import AffectedResourceList, {
|
|
|
34
34
|
AffectedResourceListDetail,
|
|
35
35
|
AffectedResourceListEntry,
|
|
36
36
|
} from "./AffectedResourceList";
|
|
37
|
+
import RootCauseList, {
|
|
38
|
+
RootCauseListDetail,
|
|
39
|
+
RootCauseListItem,
|
|
40
|
+
} from "./RootCauseList";
|
|
37
41
|
import DataToProcess from "./DataToProcess";
|
|
38
42
|
import Monitor from "../../../Models/DatabaseModels/Monitor";
|
|
39
43
|
import MonitorCriteria from "../../../Types/Monitor/MonitorCriteria";
|
|
@@ -124,6 +128,15 @@ export interface TelemetryExplorerDeepLink {
|
|
|
124
128
|
dropped: Array<string>;
|
|
125
129
|
}
|
|
126
130
|
|
|
131
|
+
/**
|
|
132
|
+
* Which affected-resources rows breached the matched criteria, and which
|
|
133
|
+
* end of the value range is the worst.
|
|
134
|
+
*/
|
|
135
|
+
interface AffectedResourceBreachPredicate {
|
|
136
|
+
matches: (value: number) => boolean;
|
|
137
|
+
worstIsLowest: boolean;
|
|
138
|
+
}
|
|
139
|
+
|
|
127
140
|
export default class MonitorCriteriaEvaluator {
|
|
128
141
|
public static async processMonitorStep(input: {
|
|
129
142
|
dataToProcess: DataToProcess;
|
|
@@ -1556,9 +1569,7 @@ ${contextBlock}
|
|
|
1556
1569
|
samples: breachingSamples,
|
|
1557
1570
|
totalSamples: ctx.totalSamplesInWindow,
|
|
1558
1571
|
unit: ctx.unit,
|
|
1559
|
-
metricName: ctx.metricName,
|
|
1560
1572
|
unitHeuristicMetricName: unitHeuristicMetricName,
|
|
1561
|
-
alias: ctx.alias,
|
|
1562
1573
|
components: ctx.components || [],
|
|
1563
1574
|
})}`,
|
|
1564
1575
|
);
|
|
@@ -1614,11 +1625,25 @@ ${contextBlock}
|
|
|
1614
1625
|
}
|
|
1615
1626
|
|
|
1616
1627
|
/**
|
|
1617
|
-
* Build the **Breaching Samples** markdown section — a
|
|
1618
|
-
*
|
|
1619
|
-
*
|
|
1620
|
-
*
|
|
1621
|
-
*
|
|
1628
|
+
* Build the **Breaching Samples** markdown section — a numbered list of
|
|
1629
|
+
* the samples that breached, oldest first. Caps the list so a 30-minute
|
|
1630
|
+
* window at 1-second granularity doesn't dump thousands of lines onto
|
|
1631
|
+
* the root-cause page; the caller can always drill in via the metric
|
|
1632
|
+
* explorer link.
|
|
1633
|
+
*
|
|
1634
|
+
* 1. `2026-08-14T10:30:00.000Z` — **1.07 GB**
|
|
1635
|
+
* - `a`: 537 MB
|
|
1636
|
+
* - `b`: 1.5 sec
|
|
1637
|
+
* - `k8s.pod.name`: `web-1`
|
|
1638
|
+
*
|
|
1639
|
+
* It used to be a table — Timestamp | Metric | Alias | Value, a column
|
|
1640
|
+
* per formula component and one per attribute key — which grew wider
|
|
1641
|
+
* with every attribute and read badly in the email card, in Slack and on
|
|
1642
|
+
* the dashboard (see RootCauseList). Its Metric and Alias columns
|
|
1643
|
+
* repeated the same two values on every row, the ones the Metric
|
|
1644
|
+
* Details list directly above already states, so the list leaves them
|
|
1645
|
+
* out; and a component or attribute a sample has no value for is left
|
|
1646
|
+
* out rather than printed as "-".
|
|
1622
1647
|
*
|
|
1623
1648
|
* Timestamps are emitted as inline code wrapping ISO 8601 strings so
|
|
1624
1649
|
* the client-side markdown viewer can localize them to the viewer's
|
|
@@ -1628,16 +1653,14 @@ ${contextBlock}
|
|
|
1628
1653
|
samples: Array<MetricBreachingSample>;
|
|
1629
1654
|
totalSamples?: number | undefined;
|
|
1630
1655
|
unit: string | null;
|
|
1631
|
-
metricName: string;
|
|
1632
1656
|
/**
|
|
1633
1657
|
* The metric name to reason about, or undefined for a formula.
|
|
1634
1658
|
* See MonitorCriteriaEvaluator.metricNameForUnitHeuristics.
|
|
1635
1659
|
*/
|
|
1636
1660
|
unitHeuristicMetricName: string | undefined;
|
|
1637
|
-
alias: string;
|
|
1638
1661
|
components: Array<MetricComponent>;
|
|
1639
1662
|
}): string {
|
|
1640
|
-
const
|
|
1663
|
+
const MAX_SAMPLES_SHOWN: number = 20;
|
|
1641
1664
|
|
|
1642
1665
|
// Sort chronologically and de-duplicate any accidental repeats
|
|
1643
1666
|
const sorted: Array<MetricBreachingSample> = [...input.samples].sort(
|
|
@@ -1650,10 +1673,13 @@ ${contextBlock}
|
|
|
1650
1673
|
|
|
1651
1674
|
const displayedSamples: Array<MetricBreachingSample> = sorted.slice(
|
|
1652
1675
|
0,
|
|
1653
|
-
|
|
1676
|
+
MAX_SAMPLES_SHOWN,
|
|
1654
1677
|
);
|
|
1655
1678
|
|
|
1656
|
-
|
|
1679
|
+
/*
|
|
1680
|
+
* Collect attribute keys that appear on any displayed sample, so every
|
|
1681
|
+
* item lists the attributes it has in the same order.
|
|
1682
|
+
*/
|
|
1657
1683
|
const attrKeySet: Set<string> = new Set<string>();
|
|
1658
1684
|
for (const s of displayedSamples) {
|
|
1659
1685
|
for (const k of Object.keys(s.attributes || {})) {
|
|
@@ -1662,107 +1688,74 @@ ${contextBlock}
|
|
|
1662
1688
|
}
|
|
1663
1689
|
const attrKeys: Array<string> = Array.from(attrKeySet);
|
|
1664
1690
|
|
|
1665
|
-
|
|
1666
|
-
|
|
1667
|
-
|
|
1668
|
-
* don't break GitHub-flavored-markdown tables.
|
|
1669
|
-
*/
|
|
1670
|
-
const escapeCell: (value: string) => string = (value: string): string => {
|
|
1671
|
-
return value.replace(/\|/g, "\\|");
|
|
1672
|
-
};
|
|
1673
|
-
|
|
1674
|
-
/*
|
|
1675
|
-
* Column layout:
|
|
1676
|
-
* Timestamp | Metric | Alias | Value | <component_1> | ... | <attr_1> | ...
|
|
1677
|
-
*
|
|
1678
|
-
* The component columns let the reader see what each variable of a
|
|
1679
|
-
* formula resolved to at the breach time — e.g. "when c = a + b
|
|
1680
|
-
* breached 100, a was 55, b was 46". They are omitted for plain
|
|
1681
|
-
* metric criteria.
|
|
1682
|
-
*/
|
|
1683
|
-
const headerCells: Array<string> = [
|
|
1684
|
-
"Timestamp",
|
|
1685
|
-
"Metric",
|
|
1686
|
-
"Alias",
|
|
1687
|
-
"Value",
|
|
1688
|
-
];
|
|
1689
|
-
|
|
1690
|
-
/*
|
|
1691
|
-
* The component columns carry no unit in their header any more. Each
|
|
1692
|
-
* cell now names the unit it actually landed on, and auto-scaling
|
|
1693
|
-
* means neighbouring rows can land on different ones — a header that
|
|
1694
|
-
* read "a (By)" over cells reading "900 KB" and "1.2 MB" states a
|
|
1695
|
-
* unit that neither row uses. The configured unit is not lost: the
|
|
1696
|
-
* Components bullet list above the table still records it.
|
|
1697
|
-
*/
|
|
1698
|
-
for (const component of input.components) {
|
|
1699
|
-
headerCells.push(component.alias);
|
|
1700
|
-
}
|
|
1701
|
-
|
|
1702
|
-
headerCells.push(...attrKeys);
|
|
1703
|
-
|
|
1704
|
-
const headerRow: string = `| ${headerCells.join(" | ")} |`;
|
|
1705
|
-
const dividerRow: string = `| ${headerCells
|
|
1706
|
-
.map(() => {
|
|
1707
|
-
return "---";
|
|
1708
|
-
})
|
|
1709
|
-
.join(" | ")} |`;
|
|
1710
|
-
|
|
1711
|
-
const metricCell: string = `\`${escapeCell(input.metricName)}\``;
|
|
1712
|
-
const aliasCell: string = input.alias
|
|
1713
|
-
? `\`${escapeCell(input.alias)}\``
|
|
1714
|
-
: "-";
|
|
1715
|
-
|
|
1716
|
-
const dataRows: Array<string> = displayedSamples.map(
|
|
1717
|
-
(s: MetricBreachingSample) => {
|
|
1718
|
-
const timestampIso: string = new Date(s.timestamp).toISOString();
|
|
1719
|
-
const cells: Array<string> = [
|
|
1720
|
-
`\`${timestampIso}\``,
|
|
1721
|
-
metricCell,
|
|
1722
|
-
aliasCell,
|
|
1723
|
-
MetricValueFormatter.format({
|
|
1724
|
-
value: s.value,
|
|
1725
|
-
unit: input.unit,
|
|
1726
|
-
metricName: input.unitHeuristicMetricName,
|
|
1727
|
-
}),
|
|
1728
|
-
];
|
|
1691
|
+
const items: Array<RootCauseListItem> = displayedSamples.map(
|
|
1692
|
+
(s: MetricBreachingSample): RootCauseListItem => {
|
|
1693
|
+
const details: Array<RootCauseListDetail> = [];
|
|
1729
1694
|
|
|
1695
|
+
/*
|
|
1696
|
+
* What each variable of a formula resolved to at the breach time —
|
|
1697
|
+
* e.g. "when c = a + b breached 100, a was 55, b was 46". Absent
|
|
1698
|
+
* for plain metric criteria.
|
|
1699
|
+
*/
|
|
1730
1700
|
for (const component of input.components) {
|
|
1731
1701
|
const match: MetricComponentValue | undefined = (
|
|
1732
1702
|
s.componentValues || []
|
|
1733
1703
|
).find((cv: MetricComponentValue) => {
|
|
1734
1704
|
return cv.alias === component.alias;
|
|
1735
1705
|
});
|
|
1736
|
-
|
|
1737
|
-
|
|
1738
|
-
|
|
1739
|
-
* indexed off the per-query series and never go through the
|
|
1740
|
-
* sample→threshold-unit conversion the main Value column
|
|
1741
|
-
* does, so they are in the component's legendUnit — mixing
|
|
1742
|
-
* units across the row is deliberate, and is why every cell
|
|
1743
|
-
* has to say which one it is in.
|
|
1744
|
-
*/
|
|
1745
|
-
cells.push(
|
|
1746
|
-
MetricValueFormatter.format({
|
|
1747
|
-
value: match.value,
|
|
1748
|
-
unit: component.unit,
|
|
1749
|
-
metricName:
|
|
1750
|
-
MonitorCriteriaEvaluator.metricNameForUnitHeuristics({
|
|
1751
|
-
metricName: component.name,
|
|
1752
|
-
isFormula: component.isFormula,
|
|
1753
|
-
}),
|
|
1754
|
-
}),
|
|
1755
|
-
);
|
|
1756
|
-
} else {
|
|
1757
|
-
cells.push("-");
|
|
1706
|
+
|
|
1707
|
+
if (!match || typeof match.value !== "number") {
|
|
1708
|
+
continue;
|
|
1758
1709
|
}
|
|
1710
|
+
|
|
1711
|
+
/*
|
|
1712
|
+
* Each component keeps its OWN unit. Component values are
|
|
1713
|
+
* indexed off the per-query series and never go through the
|
|
1714
|
+
* sample→threshold-unit conversion the sample's value does, so
|
|
1715
|
+
* they are in the component's legendUnit — which is why each
|
|
1716
|
+
* one names the unit it is in. Its configured unit is in the
|
|
1717
|
+
* Components list of the Metric Details above.
|
|
1718
|
+
*/
|
|
1719
|
+
details.push({
|
|
1720
|
+
label: RootCauseList.code(component.alias),
|
|
1721
|
+
value: MetricValueFormatter.format({
|
|
1722
|
+
value: match.value,
|
|
1723
|
+
unit: component.unit,
|
|
1724
|
+
metricName: MonitorCriteriaEvaluator.metricNameForUnitHeuristics({
|
|
1725
|
+
metricName: component.name,
|
|
1726
|
+
isFormula: component.isFormula,
|
|
1727
|
+
}),
|
|
1728
|
+
}),
|
|
1729
|
+
});
|
|
1759
1730
|
}
|
|
1760
1731
|
|
|
1732
|
+
/*
|
|
1733
|
+
* The attributes identify the series the sample came from. Keys
|
|
1734
|
+
* and values are telemetry, so both go in code spans:
|
|
1735
|
+
* RootCauseList.code keeps whatever they contain inside the span.
|
|
1736
|
+
*/
|
|
1761
1737
|
for (const k of attrKeys) {
|
|
1762
1738
|
const v: unknown = (s.attributes as Record<string, unknown>)[k];
|
|
1763
|
-
|
|
1739
|
+
|
|
1740
|
+
if (v === undefined || v === null) {
|
|
1741
|
+
continue;
|
|
1742
|
+
}
|
|
1743
|
+
|
|
1744
|
+
details.push({
|
|
1745
|
+
label: RootCauseList.code(k),
|
|
1746
|
+
value: RootCauseList.code(String(v)),
|
|
1747
|
+
});
|
|
1764
1748
|
}
|
|
1765
|
-
|
|
1749
|
+
|
|
1750
|
+
return {
|
|
1751
|
+
title: RootCauseList.code(new Date(s.timestamp).toISOString()),
|
|
1752
|
+
value: `**${MetricValueFormatter.format({
|
|
1753
|
+
value: s.value,
|
|
1754
|
+
unit: input.unit,
|
|
1755
|
+
metricName: input.unitHeuristicMetricName,
|
|
1756
|
+
})}**`,
|
|
1757
|
+
details: details,
|
|
1758
|
+
};
|
|
1766
1759
|
},
|
|
1767
1760
|
);
|
|
1768
1761
|
|
|
@@ -1773,14 +1766,17 @@ ${contextBlock}
|
|
|
1773
1766
|
totalSamples: input.totalSamples,
|
|
1774
1767
|
}),
|
|
1775
1768
|
"",
|
|
1776
|
-
|
|
1777
|
-
dividerRow,
|
|
1778
|
-
...dataRows,
|
|
1769
|
+
RootCauseList.render(items),
|
|
1779
1770
|
];
|
|
1780
1771
|
|
|
1781
1772
|
if (sorted.length > displayedSamples.length) {
|
|
1773
|
+
/*
|
|
1774
|
+
* The blank line matters: without it the note is a lazy
|
|
1775
|
+
* continuation of the last item, not a paragraph of its own.
|
|
1776
|
+
*/
|
|
1782
1777
|
lines.push(
|
|
1783
|
-
|
|
1778
|
+
"",
|
|
1779
|
+
`_Showing the first ${displayedSamples.length} of ${sorted.length} breaching samples._`,
|
|
1784
1780
|
);
|
|
1785
1781
|
}
|
|
1786
1782
|
|
|
@@ -2172,6 +2168,7 @@ ${contextBlock}
|
|
|
2172
2168
|
dataToProcess: DataToProcess;
|
|
2173
2169
|
monitorStep: MonitorStep;
|
|
2174
2170
|
monitor: Monitor;
|
|
2171
|
+
criteriaInstance?: MonitorCriteriaInstance | undefined;
|
|
2175
2172
|
}): Promise<string | null> {
|
|
2176
2173
|
const metricResponse: MetricMonitorResponse =
|
|
2177
2174
|
input.dataToProcess as MetricMonitorResponse;
|
|
@@ -2204,18 +2201,40 @@ ${contextBlock}
|
|
|
2204
2201
|
|
|
2205
2202
|
// Affected resources
|
|
2206
2203
|
if (breakdown.affectedResources && breakdown.affectedResources.length > 0) {
|
|
2207
|
-
|
|
2208
|
-
|
|
2209
|
-
|
|
2210
|
-
|
|
2211
|
-
|
|
2212
|
-
|
|
2213
|
-
|
|
2214
|
-
|
|
2215
|
-
|
|
2216
|
-
|
|
2217
|
-
|
|
2218
|
-
);
|
|
2204
|
+
/*
|
|
2205
|
+
* Keep the rows that satisfy the criteria that just matched, worst
|
|
2206
|
+
* first — NOT simply the non-zero rows. k8s-node-not-ready fires on
|
|
2207
|
+
* `k8s.node.condition_ready = 0`, so the zero rows are the NotReady
|
|
2208
|
+
* nodes; the old hardcoded `> 0` dropped exactly those and named a
|
|
2209
|
+
* healthy node in the analysis below.
|
|
2210
|
+
*/
|
|
2211
|
+
const breach: AffectedResourceBreachPredicate =
|
|
2212
|
+
MonitorCriteriaEvaluator.getAffectedResourceBreachPredicate({
|
|
2213
|
+
criteriaInstance: input.criteriaInstance,
|
|
2214
|
+
floorEqualityFiresOnFall: true,
|
|
2215
|
+
});
|
|
2216
|
+
|
|
2217
|
+
const sortedResources: Array<KubernetesAffectedResource> =
|
|
2218
|
+
breakdown.affectedResources
|
|
2219
|
+
.map((r: KubernetesAffectedResource) => {
|
|
2220
|
+
/*
|
|
2221
|
+
* A fall criteria breached on the resource's lowest sample
|
|
2222
|
+
* in the window, not its highest.
|
|
2223
|
+
*/
|
|
2224
|
+
return breach.worstIsLowest
|
|
2225
|
+
? { ...r, metricValue: r.lowestMetricValue ?? r.metricValue }
|
|
2226
|
+
: r;
|
|
2227
|
+
})
|
|
2228
|
+
.filter((r: KubernetesAffectedResource) => {
|
|
2229
|
+
return breach.matches(r.metricValue);
|
|
2230
|
+
})
|
|
2231
|
+
.sort(
|
|
2232
|
+
(a: KubernetesAffectedResource, b: KubernetesAffectedResource) => {
|
|
2233
|
+
return breach.worstIsLowest
|
|
2234
|
+
? a.metricValue - b.metricValue
|
|
2235
|
+
: b.metricValue - a.metricValue;
|
|
2236
|
+
},
|
|
2237
|
+
);
|
|
2219
2238
|
|
|
2220
2239
|
if (sortedResources.length === 0) {
|
|
2221
2240
|
return sections.join("\n");
|
|
@@ -3273,37 +3292,61 @@ ${contextBlock}
|
|
|
3273
3292
|
}
|
|
3274
3293
|
|
|
3275
3294
|
/*
|
|
3276
|
-
* Which rows of
|
|
3295
|
+
* Which rows of an affected-resources list actually BREACHED.
|
|
3277
3296
|
*
|
|
3278
3297
|
* The blanket `metricValue > 0` below is right for every count- or
|
|
3279
3298
|
* level-style criteria ("> 0 active health checks", "> 85 % used"), but
|
|
3280
|
-
* it is exactly backwards for the availability signals: the OSD
|
|
3281
|
-
* OSD Out / Quorum Degraded criteria fire on `< 1` over
|
|
3282
|
-
* ceph_osd_in / ceph_mon_quorum_status, so the ZERO rows
|
|
3283
|
-
* daemons. Dropping them rendered a list of the HEALTHY
|
|
3284
|
-
* an incident that tells the reader to "check the root
|
|
3285
|
-
* affected ceph_daemon label".
|
|
3299
|
+
* it is exactly backwards for the availability signals: the Ceph OSD
|
|
3300
|
+
* Down / OSD Out / Quorum Degraded criteria fire on `< 1` over
|
|
3301
|
+
* ceph_osd_up / ceph_osd_in / ceph_mon_quorum_status, so the ZERO rows
|
|
3302
|
+
* are the down daemons. Dropping them rendered a list of the HEALTHY
|
|
3303
|
+
* daemons under an incident that tells the reader to "check the root
|
|
3304
|
+
* cause for the affected ceph_daemon label".
|
|
3286
3305
|
*
|
|
3287
3306
|
* Invert only for a criteria that fires when the metric FALLS.
|
|
3288
3307
|
* Everything else — every `> 0` health check, PG count, latency and
|
|
3289
|
-
* capacity ratio, and every `= 0` recovery criteria —
|
|
3290
|
-
* existing `> 0`, worst-highest-first list byte for byte.
|
|
3308
|
+
* capacity ratio, and (by default) every `= 0` recovery criteria —
|
|
3309
|
+
* keeps the existing `> 0`, worst-highest-first list byte for byte.
|
|
3310
|
+
*
|
|
3311
|
+
* `floorEqualityFiresOnFall` additionally counts a FIRING `= 0` (or
|
|
3312
|
+
* below) as a fall. Kubernetes needs it: k8s-node-not-ready and
|
|
3313
|
+
* k8s-etcd-no-leader fire on `= 0` over k8s.node.condition_ready /
|
|
3314
|
+
* etcd_server_has_leader, and zero is the floor of those metrics, so
|
|
3315
|
+
* the only way to reach it is down. It is gated on the criteria opening
|
|
3316
|
+
* an incident or alert because the same `= 0` is also how the restart,
|
|
3317
|
+
* failed-pod and unavailable-replica templates express RECOVERY, and
|
|
3318
|
+
* that all-clear must not become a list of healthy zero rows. Ceph
|
|
3319
|
+
* leaves it off: all of its `= 0` criteria are recoveries.
|
|
3291
3320
|
*/
|
|
3292
|
-
private static
|
|
3293
|
-
criteriaInstance?: MonitorCriteriaInstance | undefined
|
|
3294
|
-
|
|
3321
|
+
private static getAffectedResourceBreachPredicate(input: {
|
|
3322
|
+
criteriaInstance?: MonitorCriteriaInstance | undefined;
|
|
3323
|
+
floorEqualityFiresOnFall?: boolean | undefined;
|
|
3324
|
+
}): AffectedResourceBreachPredicate {
|
|
3295
3325
|
const metricFilters: Array<CriteriaFilter> = (
|
|
3296
|
-
criteriaInstance?.data?.filters || []
|
|
3326
|
+
input.criteriaInstance?.data?.filters || []
|
|
3297
3327
|
).filter((f: CriteriaFilter) => {
|
|
3298
3328
|
return f.checkOn === CheckOn.MetricValue && typeof f.value === "number";
|
|
3299
3329
|
});
|
|
3300
3330
|
|
|
3331
|
+
const opensIncidentOrAlert: boolean =
|
|
3332
|
+
input.criteriaInstance?.data?.createIncidents === true ||
|
|
3333
|
+
input.criteriaInstance?.data?.createAlerts === true;
|
|
3334
|
+
|
|
3301
3335
|
const firesWhenMetricFalls: boolean =
|
|
3302
3336
|
metricFilters.length > 0 &&
|
|
3303
3337
|
metricFilters.every((f: CriteriaFilter) => {
|
|
3304
|
-
|
|
3338
|
+
if (
|
|
3305
3339
|
f.filterType === FilterType.LessThan ||
|
|
3306
3340
|
f.filterType === FilterType.LessThanOrEqualTo
|
|
3341
|
+
) {
|
|
3342
|
+
return true;
|
|
3343
|
+
}
|
|
3344
|
+
|
|
3345
|
+
return (
|
|
3346
|
+
input.floorEqualityFiresOnFall === true &&
|
|
3347
|
+
opensIncidentOrAlert &&
|
|
3348
|
+
f.filterType === FilterType.EqualTo &&
|
|
3349
|
+
(f.value as number) <= 0
|
|
3307
3350
|
);
|
|
3308
3351
|
});
|
|
3309
3352
|
|
|
@@ -3321,6 +3364,10 @@ ${contextBlock}
|
|
|
3321
3364
|
return metricFilters.some((f: CriteriaFilter) => {
|
|
3322
3365
|
const threshold: number = f.value as number;
|
|
3323
3366
|
|
|
3367
|
+
if (f.filterType === FilterType.EqualTo) {
|
|
3368
|
+
return value === threshold;
|
|
3369
|
+
}
|
|
3370
|
+
|
|
3324
3371
|
return f.filterType === FilterType.LessThan
|
|
3325
3372
|
? value < threshold
|
|
3326
3373
|
: value <= threshold;
|
|
@@ -3478,12 +3525,10 @@ ${contextBlock}
|
|
|
3478
3525
|
* ceph_osd_in / ceph_mon_quorum_status the criteria is `< 1`, so
|
|
3479
3526
|
* the zero rows are the whole point of the incident.
|
|
3480
3527
|
*/
|
|
3481
|
-
const breach:
|
|
3482
|
-
|
|
3483
|
-
|
|
3484
|
-
|
|
3485
|
-
input.criteriaInstance,
|
|
3486
|
-
);
|
|
3528
|
+
const breach: AffectedResourceBreachPredicate =
|
|
3529
|
+
MonitorCriteriaEvaluator.getAffectedResourceBreachPredicate({
|
|
3530
|
+
criteriaInstance: input.criteriaInstance,
|
|
3531
|
+
});
|
|
3487
3532
|
|
|
3488
3533
|
const sortedResources: Array<CephAffectedResource> = [
|
|
3489
3534
|
...breakdown.affectedResources,
|