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 <paulus@home-assistant.io>

* Fix format

Co-authored-by: Paulus Schoutsen <paulus@home-assistant.io>
pull/47651/head
Erik Montnemery 2021-03-08 22:48:36 +01:00 committed by GitHub
parent 665e2c3473
commit ea4f3e31d5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 18 additions and 5 deletions

View File

@ -120,7 +120,7 @@ _TIMEOUT_MSG = "Timeout reached, abort script."
_SHUTDOWN_MAX_WAIT = 60 _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): def action_trace_append(variables, path):
@ -294,7 +294,7 @@ class _ScriptRun:
self._finish() self._finish()
async def _async_step(self, log_exceptions): 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: try:
handler = f"_async_{cv.determine_script_action(self._action)}_step" handler = f"_async_{cv.determine_script_action(self._action)}_step"
await getattr(self, handler)() await getattr(self, handler)()

View File

@ -16,7 +16,17 @@ class TraceElement:
self._error: Optional[Exception] = None self._error: Optional[Exception] = None
self._result: Optional[dict] = None self._result: Optional[dict] = None
self._timestamp = dt_util.utcnow() 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: def __repr__(self) -> str:
"""Container for trace data.""" """Container for trace data."""
@ -33,8 +43,8 @@ class TraceElement:
def as_dict(self) -> Dict[str, Any]: def as_dict(self) -> Dict[str, Any]:
"""Return dictionary version of this TraceElement.""" """Return dictionary version of this TraceElement."""
result: Dict[str, Any] = {"timestamp": self._timestamp} result: Dict[str, Any] = {"timestamp": self._timestamp}
# Commented out because we get too many copies of the same data if self._variables:
# result["variables"] = self._variables result["changed_variables"] = self._variables
if self._error is not None: if self._error is not None:
result["error"] = str(self._error) result["error"] = str(self._error)
if self._result is not None: 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: ContextVar[Optional[List[str]]] = ContextVar(
"trace_path_stack_cv", default=None "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: def trace_stack_push(trace_stack_var: ContextVar, node: Any) -> None:
@ -128,6 +140,7 @@ def trace_clear() -> None:
trace_cv.set({}) trace_cv.set({})
trace_stack_cv.set(None) trace_stack_cv.set(None)
trace_path_stack_cv.set(None) trace_path_stack_cv.set(None)
variables_cv.set(None)
def trace_set_result(**kwargs: Any) -> None: def trace_set_result(**kwargs: Any) -> None: