feat(traefik): a 4xx share is worth a look only once it is a lot of 4xx (#6105)
Three 404s on a quiet router read 7.5% and were raised as an anomaly; most of the 4xx anomalies on review stood for 3 to 7 errors in 15 minutes. A new Settings → Thresholds minimum, traefik.threshold.min_4xx (default 20, more than one a minute held for the window), applies to both the router's grade on its page and to anomaly detection, as min_5xx does for 5xx. learn_normal takes `fewest`: for a share gated on a per-second rate, the fewest events (rate × window × share) it must stand for to be judged. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
+10
-3
@@ -57,7 +57,11 @@ class Learned:
|
||||
`gate` is (metric, least): the resource is judged only while that metric
|
||||
of its own averages at least `least` over the window, as a router's
|
||||
error share means nothing over a handful of requests (#5741). `least`
|
||||
may be a function, read at each pass, for a minimum that is a setting. `since`:
|
||||
may be a function, read at each pass, for a minimum that is a setting.
|
||||
`fewest`, for a share (%) gated on a per-second rate: the fewest events
|
||||
the share stands for over the window (rate × window × share / 100), as
|
||||
three 404s are 7% of a quiet router and no news (#6105); a number or a
|
||||
function, like `least`. `since`:
|
||||
history before it is not learned from, for a metric whose meaning
|
||||
changed then. `parts=False` learns only whole resources, not their parts
|
||||
("<host>:core3"): a host's CPU has a normal, each of its cores doesn't."""
|
||||
@@ -67,6 +71,7 @@ class Learned:
|
||||
gate: tuple[str, float | Callable[[], float]] | None = None
|
||||
since: datetime | None = None
|
||||
parts: bool = True
|
||||
fewest: float | Callable[[], float] | None = None
|
||||
|
||||
@property
|
||||
def least_departure(self) -> float:
|
||||
@@ -83,11 +88,13 @@ LEARNED: dict[tuple[str, str], Learned] = {}
|
||||
|
||||
def learn_normal(source_module: str, metric_name: str, floor: float | Callable[[], float], *,
|
||||
gate: tuple[str, float | Callable[[], float]] | None = None,
|
||||
since: datetime | None = None, parts: bool = True) -> None:
|
||||
since: datetime | None = None, parts: bool = True,
|
||||
fewest: float | Callable[[], float] | None = None) -> None:
|
||||
"""Have Steward learn this metric's normal for every resource reporting
|
||||
it. A plugin calls this from setup(), as it calls prune_by_age."""
|
||||
LEARNED[(source_module, metric_name)] = Learned(
|
||||
source_module, metric_name, floor if callable(floor) else float(floor), gate, since, parts)
|
||||
source_module, metric_name, floor if callable(floor) else float(floor), gate, since, parts,
|
||||
fewest)
|
||||
|
||||
|
||||
def floor_setting(app, name: str) -> Callable[[], float]:
|
||||
|
||||
Reference in New Issue
Block a user