From ea4f3e31d58f8473b7af6bfd85d51196ac66e451 Mon Sep 17 00:00:00 2001 From: Erik Montnemery Date: Mon, 8 Mar 2021 22:48:36 +0100 Subject: [PATCH] Include changed variables in automation trace (#47549) * Include changed variables in automation trace * Deduplicate some code * Tweak * Apply suggestions from code review Co-authored-by: Paulus Schoutsen * Fix format Co-authored-by: Paulus Schoutsen --- homeassistant/helpers/script.py | 4 ++-- homeassistant/helpers/trace.py | 19 ++++++++++++++++--- 2 files changed, 18 insertions(+), 5 deletions(-) diff --git a/homeassistant/helpers/script.py b/homeassistant/helpers/script.py index 8ee9b12bc1b..b3fcffd4944 100644 --- a/homeassistant/helpers/script.py +++ b/homeassistant/helpers/script.py @@ -120,7 +120,7 @@ _TIMEOUT_MSG = "Timeout reached, abort script." _SHUTDOWN_MAX_WAIT = 60 -ACTION_TRACE_NODE_MAX_LEN = 20 # Max the length of a trace node for repeated actions +ACTION_TRACE_NODE_MAX_LEN = 20 # Max length of a trace node for repeated actions def action_trace_append(variables, path): @@ -294,7 +294,7 @@ class _ScriptRun: self._finish() async def _async_step(self, log_exceptions): - with trace_path(str(self._step)), trace_action(None): + with trace_path(str(self._step)), trace_action(self._variables): try: handler = f"_async_{cv.determine_script_action(self._action)}_step" await getattr(self, handler)() diff --git a/homeassistant/helpers/trace.py b/homeassistant/helpers/trace.py index 8c5c181ea24..0c1969a8ac6 100644 --- a/homeassistant/helpers/trace.py +++ b/homeassistant/helpers/trace.py @@ -16,7 +16,17 @@ class TraceElement: self._error: Optional[Exception] = None self._result: Optional[dict] = None self._timestamp = dt_util.utcnow() - self._variables = variables + + if variables is None: + variables = {} + last_variables = variables_cv.get() or {} + variables_cv.set(dict(variables)) + changed_variables = { + key: value + for key, value in variables.items() + if key not in last_variables or last_variables[key] != value + } + self._variables = changed_variables def __repr__(self) -> str: """Container for trace data.""" @@ -33,8 +43,8 @@ class TraceElement: def as_dict(self) -> Dict[str, Any]: """Return dictionary version of this TraceElement.""" result: Dict[str, Any] = {"timestamp": self._timestamp} - # Commented out because we get too many copies of the same data - # result["variables"] = self._variables + if self._variables: + result["changed_variables"] = self._variables if self._error is not None: result["error"] = str(self._error) if self._result is not None: @@ -55,6 +65,8 @@ trace_stack_cv: ContextVar[Optional[List[TraceElement]]] = ContextVar( trace_path_stack_cv: ContextVar[Optional[List[str]]] = ContextVar( "trace_path_stack_cv", default=None ) +# Copy of last variables +variables_cv: ContextVar[Optional[Any]] = ContextVar("variables_cv", default=None) def trace_stack_push(trace_stack_var: ContextVar, node: Any) -> None: @@ -128,6 +140,7 @@ def trace_clear() -> None: trace_cv.set({}) trace_stack_cv.set(None) trace_path_stack_cv.set(None) + variables_cv.set(None) def trace_set_result(**kwargs: Any) -> None: