included cloud logging with filters
This commit is contained in:
@@ -0,0 +1,80 @@
|
||||
"""Send controller events to the cloud event logger."""
|
||||
|
||||
import logging
|
||||
from datetime import datetime, timezone
|
||||
|
||||
import requests
|
||||
|
||||
|
||||
LOG = logging.getLogger("home_control.cloud_logger")
|
||||
|
||||
|
||||
def _filter_values(config: dict, mode: str, field: str) -> set[str]:
|
||||
value = config.get("filter", {}).get(mode, {}).get(field, [])
|
||||
if not isinstance(value, list) or any(not isinstance(item, str) for item in value):
|
||||
raise ValueError(
|
||||
f"cloud_logger.filter.{mode}.{field} must be a list of strings"
|
||||
)
|
||||
return set(value)
|
||||
|
||||
|
||||
def accepts_event(config: dict, message: dict) -> bool:
|
||||
"""Return whether an event passes configured event and ID filters."""
|
||||
accepted_events = _filter_values(config, "accept", "events")
|
||||
accepted_ids = _filter_values(config, "accept", "ids")
|
||||
ignored_events = _filter_values(config, "ignore", "events")
|
||||
ignored_ids = _filter_values(config, "ignore", "ids")
|
||||
|
||||
if message["event"] in ignored_events or message["id"] in ignored_ids:
|
||||
return False
|
||||
if accepted_events and message["event"] not in accepted_events:
|
||||
return False
|
||||
if accepted_ids and message["id"] not in accepted_ids:
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
def send_event(message: dict, event_url: str, timeout: float = 10) -> None:
|
||||
"""POST an event dictionary as JSON to the configured logger endpoint."""
|
||||
if not isinstance(message, dict):
|
||||
raise TypeError("message must be a dictionary")
|
||||
if not event_url:
|
||||
raise ValueError("event_url is required")
|
||||
|
||||
response = requests.post(event_url, json=message, timeout=timeout)
|
||||
response.raise_for_status()
|
||||
|
||||
|
||||
def on_event(config: dict, message: dict) -> None:
|
||||
"""Controller action that forwards event data to the cloud logger."""
|
||||
if not config.get("enabled", True):
|
||||
return
|
||||
|
||||
try:
|
||||
if not accepts_event(config, message):
|
||||
LOG.debug(
|
||||
"cloud event ignored by filter: event=%s id=%s",
|
||||
message["event"],
|
||||
message["id"],
|
||||
)
|
||||
return
|
||||
|
||||
timestamp = datetime.now(timezone.utc).isoformat()
|
||||
values = {**message, "datetime": timestamp}
|
||||
messages = config.get("messages", {})
|
||||
template = messages.get(
|
||||
message["event"],
|
||||
config.get("message", "{datetime} {sender}: {event} ({id})"),
|
||||
)
|
||||
payload = {
|
||||
**message,
|
||||
"datetime": timestamp,
|
||||
"text": message.get("text") or str(template).format(**values),
|
||||
}
|
||||
send_event(
|
||||
payload,
|
||||
event_url=str(config.get("event_url", "")),
|
||||
timeout=float(config.get("timeout", 10)),
|
||||
)
|
||||
except (TypeError, ValueError, requests.RequestException) as error:
|
||||
LOG.error("cloud event logging failed: %s", error)
|
||||
Reference in New Issue
Block a user