4b6817381b
CI (OpenClaw E2E) / openclaw test (push) Has been cancelled
CI / coverage-report (push) Has been cancelled
CI / test-kubernetes (push) Has been cancelled
CI / should-run-thorough (push) Has been cancelled
CI / test-thorough (cloudwatch-demo) (push) Has been cancelled
CI / test-thorough (flink-ecs) (push) Has been cancelled
CI / test-thorough (upstream-lambda) (push) Has been cancelled
CI / test-thorough (prefect-ecs-fargate) (push) Has been cancelled
Release / build-binaries (zip, opensre.exe, onefile, windows-latest, windows-x64) (push) Has been cancelled
Benchmark image — build + push to ECR (any adapter) / build + push (push) Has been cancelled
CI / quality (ubuntu-latest) (push) Has been cancelled
CI / test (tools-runtime) (push) Has been cancelled
CI / test (e2e-general) (push) Has been cancelled
CI / test (cli-runtime) (push) Has been cancelled
CI / test (e2e-provider-and-openclaw) (push) Has been cancelled
CI / test (integrations-and-misc) (push) Has been cancelled
Release / verify (push) Has been cancelled
Release / build-python-dist (push) Has been cancelled
Release / build-binaries (tar.gz, opensre, onedir, macos-15-intel, darwin-x64) (push) Has been cancelled
Release / build-binaries (tar.gz, opensre, onedir, macos-latest, darwin-arm64) (push) Has been cancelled
Release / build-binaries (tar.gz, opensre, onedir, ubuntu-22.04, linux-x64) (push) Has been cancelled
Release / publish-release (push) Has been cancelled
Release / publish-main-release (push) Has been cancelled
Interactive Shell Live (PR + post-merge) / turn-checks (no-LLM) (push) Has been cancelled
CodeQL / Analyze (python) (push) Has been cancelled
Interactive Shell Live (PR + post-merge) / turn-live shard ${{ matrix.shard_index }} (push) Has been cancelled
Release / prepare (push) Has been cancelled
Release / build-binaries (tar.gz, opensre, onedir, ubuntu-22.04-arm, linux-arm64) (push) Has been cancelled
Synthetic Deterministic Tests / Synthetic offline (deterministic) (push) Has been cancelled
129 lines
4.4 KiB
Python
129 lines
4.4 KiB
Python
"""Shared alert field precedence and payload-shape helpers."""
|
|
|
|
from __future__ import annotations
|
|
|
|
from collections.abc import Iterator, Mapping
|
|
from typing import Any, Final
|
|
|
|
ALERT_BLOCK_KEYS: Final[tuple[str, ...]] = (
|
|
"commonAnnotations",
|
|
"annotations",
|
|
"commonLabels",
|
|
"labels",
|
|
)
|
|
|
|
ALERT_NAME_RAW_KEYS: Final[tuple[str, ...]] = ("alert_name", "title")
|
|
ALERT_NAME_CANONICAL_KEYS: Final[tuple[str, ...]] = ("alert_name",)
|
|
ALERT_NAME_LABEL_KEYS: Final[tuple[str, ...]] = ("alertname", "alert_name")
|
|
ALERT_NAME_ANNOTATION_KEYS: Final[tuple[str, ...]] = ("summary",)
|
|
|
|
PIPELINE_NAME_RAW_KEYS: Final[tuple[str, ...]] = ("pipeline_name",)
|
|
PIPELINE_NAME_CANONICAL_KEYS: Final[tuple[str, ...]] = ("pipeline_name",)
|
|
PIPELINE_NAME_LABEL_KEYS: Final[tuple[str, ...]] = ("pipeline_name", "pipeline", "service")
|
|
PIPELINE_NAME_ANNOTATION_KEYS: Final[tuple[str, ...]] = ("pipeline_name",)
|
|
PIPELINE_NAME_FALLBACK_RAW_KEYS: Final[tuple[str, ...]] = ("service",)
|
|
|
|
SEVERITY_RAW_KEYS: Final[tuple[str, ...]] = ("severity",)
|
|
SEVERITY_CANONICAL_KEYS: Final[tuple[str, ...]] = ("severity",)
|
|
SEVERITY_LABEL_KEYS: Final[tuple[str, ...]] = ("severity", "priority")
|
|
|
|
|
|
def dict_value(source: Mapping[str, Any], key: str) -> dict[str, Any]:
|
|
"""Return a copied dict value from ``source`` or an empty dict."""
|
|
value = source.get(key)
|
|
return dict(value) if isinstance(value, dict) else {}
|
|
|
|
|
|
def first_present(*values: Any) -> Any:
|
|
"""Return the first value that is not ``None`` or a blank string."""
|
|
for value in values:
|
|
if value is None:
|
|
continue
|
|
if isinstance(value, str) and not value.strip():
|
|
continue
|
|
return value
|
|
return None
|
|
|
|
|
|
def first_text(*values: Any, default: str = "") -> str:
|
|
"""Return the first present value coerced to stripped text."""
|
|
value = first_present(*values)
|
|
if value is None:
|
|
return default
|
|
return str(value).strip()
|
|
|
|
|
|
def first_mapping_value(source: Mapping[str, Any], keys: tuple[str, ...]) -> Any:
|
|
"""Return the first present value for ``keys`` from ``source``."""
|
|
return first_present(*(source.get(key) for key in keys))
|
|
|
|
|
|
def alert_labels(raw_alert: Mapping[str, Any]) -> dict[str, Any]:
|
|
return dict_value(raw_alert, "commonLabels") or dict_value(raw_alert, "labels")
|
|
|
|
|
|
def alert_annotations(raw_alert: Mapping[str, Any]) -> dict[str, Any]:
|
|
return dict_value(raw_alert, "commonAnnotations") or dict_value(raw_alert, "annotations")
|
|
|
|
|
|
def canonical_alert(raw_alert: Mapping[str, Any]) -> dict[str, Any]:
|
|
return dict_value(raw_alert, "canonical_alert")
|
|
|
|
|
|
def iter_alert_blocks(raw_alert: Mapping[str, Any]) -> Iterator[dict[str, Any]]:
|
|
"""Yield annotation/label blocks in stable alert-webhook precedence order."""
|
|
for key in ALERT_BLOCK_KEYS:
|
|
value = raw_alert.get(key)
|
|
if isinstance(value, dict):
|
|
yield dict(value)
|
|
|
|
|
|
def alert_name_value(
|
|
raw_alert: Mapping[str, Any],
|
|
*,
|
|
labels: Mapping[str, Any] | None = None,
|
|
annotations: Mapping[str, Any] | None = None,
|
|
canonical: Mapping[str, Any] | None = None,
|
|
fallback: Any = None,
|
|
) -> Any:
|
|
return first_present(
|
|
first_mapping_value(raw_alert, ALERT_NAME_RAW_KEYS),
|
|
first_mapping_value(canonical or {}, ALERT_NAME_CANONICAL_KEYS),
|
|
first_mapping_value(labels or {}, ALERT_NAME_LABEL_KEYS),
|
|
first_mapping_value(annotations or {}, ALERT_NAME_ANNOTATION_KEYS),
|
|
fallback,
|
|
)
|
|
|
|
|
|
def pipeline_name_value(
|
|
raw_alert: Mapping[str, Any],
|
|
*,
|
|
labels: Mapping[str, Any] | None = None,
|
|
annotations: Mapping[str, Any] | None = None,
|
|
canonical: Mapping[str, Any] | None = None,
|
|
fallback: Any = None,
|
|
) -> Any:
|
|
return first_present(
|
|
first_mapping_value(raw_alert, PIPELINE_NAME_RAW_KEYS),
|
|
first_mapping_value(canonical or {}, PIPELINE_NAME_CANONICAL_KEYS),
|
|
first_mapping_value(labels or {}, PIPELINE_NAME_LABEL_KEYS),
|
|
first_mapping_value(annotations or {}, PIPELINE_NAME_ANNOTATION_KEYS),
|
|
first_mapping_value(raw_alert, PIPELINE_NAME_FALLBACK_RAW_KEYS),
|
|
fallback,
|
|
)
|
|
|
|
|
|
def severity_value(
|
|
raw_alert: Mapping[str, Any],
|
|
*,
|
|
labels: Mapping[str, Any] | None = None,
|
|
canonical: Mapping[str, Any] | None = None,
|
|
fallback: Any = None,
|
|
) -> Any:
|
|
return first_present(
|
|
first_mapping_value(raw_alert, SEVERITY_RAW_KEYS),
|
|
first_mapping_value(canonical or {}, SEVERITY_CANONICAL_KEYS),
|
|
first_mapping_value(labels or {}, SEVERITY_LABEL_KEYS),
|
|
fallback,
|
|
)
|