Init Commit: fix for issue #4510

Signed-off-by: Sahil Rasaikar <sahil.rasaikar@gmail.com>
This commit is contained in:
Sahil Rasaikar 2025-08-17 16:18:02 +05:30
parent f4b8840f51
commit 516afbea67
3 changed files with 31 additions and 5 deletions

View File

@ -58,6 +58,8 @@ const (
// StateFiring is the state of an alert that has been active for longer than // StateFiring is the state of an alert that has been active for longer than
// the configured threshold duration. // the configured threshold duration.
StateFiring StateFiring
// StateUnknown is the state of an alert that has not yet been evaluated.
StateUnknown
) )
func (s AlertState) String() string { func (s AlertState) String() string {
@ -68,6 +70,8 @@ func (s AlertState) String() string {
return "pending" return "pending"
case StateFiring: case StateFiring:
return "firing" return "firing"
case StateUnknown:
return "unknown"
} }
panic(fmt.Errorf("unknown alert state: %d", s)) panic(fmt.Errorf("unknown alert state: %d", s))
} }
@ -530,8 +534,13 @@ func (r *AlertingRule) Eval(ctx context.Context, queryOffset time.Duration, ts t
} }
// State returns the maximum state of alert instances for this rule. // State returns the maximum state of alert instances for this rule.
// StateFiring > StatePending > StateInactive. // StateFiring > StatePending > StateInactive > StateUnknown.
func (r *AlertingRule) State() AlertState { func (r *AlertingRule) State() AlertState {
// If the rule has never been evaluated, return StateUnknown
if r.GetEvaluationTimestamp().IsZero() {
return StateUnknown
}
r.activeMtx.Lock() r.activeMtx.Lock()
defer r.activeMtx.Unlock() defer r.activeMtx.Unlock()

View File

@ -1,4 +1,4 @@
type RuleState = "pending" | "firing" | "inactive"; type RuleState = "pending" | "firing" | "inactive" | "unknown";
export interface Alert { export interface Alert {
labels: Record<string, string>; labels: Record<string, string>;

View File

@ -45,6 +45,7 @@ type AlertsPageData = {
inactive: number; inactive: number;
pending: number; pending: number;
firing: number; firing: number;
unknown: number;
}; };
groups: { groups: {
name: string; name: string;
@ -55,6 +56,7 @@ type AlertsPageData = {
inactive: number; inactive: number;
pending: number; pending: number;
firing: number; firing: number;
unknown: number;
}; };
rules: { rules: {
rule: AlertingRule; rule: AlertingRule;
@ -82,6 +84,7 @@ const buildAlertsPageData = (
inactive: 0, inactive: 0,
pending: 0, pending: 0,
firing: 0, firing: 0,
unknown: 0,
}, },
groups: [], groups: [],
}; };
@ -92,6 +95,7 @@ const buildAlertsPageData = (
inactive: 0, inactive: 0,
pending: 0, pending: 0,
firing: 0, firing: 0,
unknown: 0,
}; };
for (const r of group.rules) { for (const r of group.rules) {
@ -109,6 +113,10 @@ const buildAlertsPageData = (
pageData.globalCounts.pending++; pageData.globalCounts.pending++;
groupCounts.pending++; groupCounts.pending++;
break; break;
case "unknown":
pageData.globalCounts.unknown++;
groupCounts.unknown++;
break;
default: default:
throw new Error(`Unknown rule state: ${r.state}`); throw new Error(`Unknown rule state: ${r.state}`);
} }
@ -239,6 +247,11 @@ export default function AlertsPage() {
pending ({g.counts.pending}) pending ({g.counts.pending})
</Badge> </Badge>
)} )}
{g.counts.unknown > 0 && (
<Badge className={badgeClasses.healthUnknown}>
unknown ({g.counts.unknown})
</Badge>
)}
{g.counts.inactive > 0 && ( {g.counts.inactive > 0 && (
<Badge className={badgeClasses.healthOk}> <Badge className={badgeClasses.healthOk}>
inactive ({g.counts.inactive}) inactive ({g.counts.inactive})
@ -285,6 +298,8 @@ export default function AlertsPage() {
? panelClasses.panelHealthErr ? panelClasses.panelHealthErr
: r.counts.pending > 0 : r.counts.pending > 0
? panelClasses.panelHealthWarn ? panelClasses.panelHealthWarn
: r.rule.state === "unknown"
? panelClasses.panelHealthUnknown
: panelClasses.panelHealthOk : panelClasses.panelHealthOk
} }
> >
@ -401,13 +416,15 @@ export default function AlertsPage() {
<Stack mt="xs"> <Stack mt="xs">
<Group> <Group>
<StateMultiSelect <StateMultiSelect
options={["inactive", "pending", "firing"]} options={["inactive", "pending", "firing", "unknown"]}
optionClass={(o) => optionClass={(o) =>
o === "inactive" o === "inactive"
? badgeClasses.healthOk ? badgeClasses.healthOk
: o === "pending" : o === "pending"
? badgeClasses.healthWarn ? badgeClasses.healthWarn
: badgeClasses.healthErr : o === "firing"
? badgeClasses.healthErr
: badgeClasses.healthUnknown
} }
optionCount={(o) => optionCount={(o) =>
alertsPageData.globalCounts[ alertsPageData.globalCounts[