Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions dora_monitor/config.example.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,13 @@ dora_url: "https://dora.bal-devnet-7.ethpandaops.io"
# in the Dora API. Any name containing this is considered "ours".
client_match: "ethrex"

# Optional: substrings (case-insensitive) for clients that match client_match
# but should be dropped entirely — no alerts AND excluded from the heartbeat.
# Use for deliberately-misbehaving nodes (e.g. a "deathstar" proposer that
# builds on empty / withholds PTC votes by design).
# client_exclude:
# - "lodestar-ethrex-1"

# Slack incoming webhook URL. Can also be set via SLACK_WEBHOOK_URL env var.
# Leave empty to disable Slack delivery.
slack_webhook_url: ""
Expand Down
19 changes: 15 additions & 4 deletions dora_monitor/dora_monitor/checks.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,15 @@ def _matches(name: str | None, needle: str) -> bool:
return needle.lower() in name.lower()


def _excluded(name: str | None, cfg: Config) -> bool:
return any(_matches(name, ex) for ex in cfg.client_exclude)


def _is_ours(name: str | None, cfg: Config) -> bool:
"""Matches `client_match` and is not muted via `client_exclude`."""
return _matches(name, cfg.client_match) and not _excluded(name, cfg)


def _burst_update_interval_s(schedule_min: list[int], update_count: int) -> int:
"""Pick the next update interval (seconds) for a burst.

Expand Down Expand Up @@ -84,7 +93,7 @@ def check_missed_blocks(
slots = dora.slots(limit=cfg.slot_scan_limit, with_orphaned=1, with_missing=1)
for s in slots:
proposer_name = s.get("proposer_name") or ""
if not _matches(proposer_name, cfg.client_match):
if not _is_ours(proposer_name, cfg):
continue
slot_num = int(s.get("slot", 0))
status = (s.get("status") or "").lower()
Expand Down Expand Up @@ -195,7 +204,7 @@ def check_client_head_forks(
is_canonical = head_root == canonical_root
for client in fork.get("clients") or []:
name = client.get("name") or ""
if not _matches(name, cfg.client_match):
if not _is_ours(name, cfg):
continue
status = (client.get("status") or "").lower()
client_head = int(client.get("head_slot") or head_slot)
Expand Down Expand Up @@ -301,7 +310,7 @@ def check_version_drift(
"""
versions = dora.execution_versions()
for name, version in versions.items():
if not _matches(name, cfg.client_match):
if not _is_ours(name, cfg):
continue
prev = state.client_versions.get(name)
if prev is None:
Expand Down Expand Up @@ -418,6 +427,8 @@ def _gather_heartbeat(dora: DoraClient, cfg: Config) -> HeartbeatData:
for fork in forks:
for client in fork.get("clients") or []:
name = client.get("name") or ""
if _excluded(name, cfg):
continue
status = (client.get("status") or "unknown").lower()
entry = {
"name": name,
Expand All @@ -435,7 +446,7 @@ def _gather_heartbeat(dora: DoraClient, cfg: Config) -> HeartbeatData:
data.window = max(cfg.heartbeat_slot_window, 1)
slots = dora.slots(limit=data.window, with_orphaned=1, with_missing=1)
for s in slots:
if not _matches(s.get("proposer_name") or "", cfg.client_match):
if not _is_ours(s.get("proposer_name") or "", cfg):
continue
data.total_matched_proposals += 1
st = (s.get("status") or "").lower()
Expand Down
4 changes: 4 additions & 0 deletions dora_monitor/dora_monitor/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@ class Checks:
class Config:
dora_url: str
client_match: str = "ethrex"
# Substrings (case-insensitive) for clients that match `client_match` but
# should be dropped entirely: no alerts and excluded from the heartbeat.
# Use for deliberately-misbehaving nodes (e.g. a "deathstar" proposer).
client_exclude: list[str] = field(default_factory=list)
slack_webhook_url: str = ""
discord_webhook_url: str = ""
network_label: str = ""
Expand Down