From 821b4ea4f40de1808c57ae2ea590861dfdcf68c2 Mon Sep 17 00:00:00 2001 From: Iisakki Rotko Date: Thu, 22 Feb 2024 15:31:49 +0100 Subject: [PATCH] feat: improve logging of reactive variable changes --- solara/__main__.py | 3 +++ solara/server/settings.py | 1 + solara/toestand.py | 39 ++++++++++++++++++++++++++++++++++++++- 3 files changed, 42 insertions(+), 1 deletion(-) diff --git a/solara/__main__.py b/solara/__main__.py index da34c1b34..6c5a4bf80 100644 --- a/solara/__main__.py +++ b/solara/__main__.py @@ -367,7 +367,10 @@ def open_browser(): if log_level is not None: LOGGING_CONFIG["loggers"]["solara"]["level"] = log_level.upper() + settings.main.log_level = log_level.upper() # LOGGING_CONFIG["loggers"]["reacton"]["level"] = log_level.upper() + else: + settings.main.log_level = "ERROR" log_level = log_level_uvicorn del log_level_uvicorn diff --git a/solara/server/settings.py b/solara/server/settings.py index 9d4007603..82eededb2 100644 --- a/solara/server/settings.py +++ b/solara/server/settings.py @@ -151,6 +151,7 @@ class MainSettings(BaseSettings): platform: str = sys.platform host: str = HOST_DEFAULT experimental_performance: bool = False + log_level: str = "INFO" class Config: env_prefix = "solara_" diff --git a/solara/toestand.py b/solara/toestand.py index 247bb68b3..dd62f3074 100644 --- a/solara/toestand.py +++ b/solara/toestand.py @@ -28,11 +28,13 @@ import solara from solara import _using_solara_server +from solara.server import settings T = TypeVar("T") TS = TypeVar("TS") S = TypeVar("S") # used for state logger = logging.getLogger("solara.toestand") +solara_logger = logging.getLogger("solara") _DEBUG = False @@ -86,6 +88,38 @@ def __init__(self, merge: Callable = merge_state): self.merge = merge self.listeners: Dict[str, Set[Tuple[Callable[[T], None], Optional[ContextManager]]]] = defaultdict(set) self.listeners2: Dict[str, Set[Tuple[Callable[[T, T], None], Optional[ContextManager]]]] = defaultdict(set) + if settings.main.log_level in ["DEBUG", "INFO"]: + import inspect + + for frame in inspect.stack(): + file = frame.filename + if ( + not ( + file.endswith("solara/toestand.py") + or file.endswith("solara/reactive.py") + or file.endswith("solara/hooks/use_reactive.py") + or file.endswith("reacton/core.py") + or file.endswith("components/markdown.py") + ) + and frame.code_context is not None + ): + if "=" not in frame.code_context[0]: + continue + elif any(op in frame.code_context[0].split("=")[1].lower() for op in ["reactive", "use_memo", "computed", "singleton"]): + declaration = frame.code_context[0].split("=")[0].strip() + if ":" in declaration: + declaration = declaration.split(":")[0].strip() + self._varname: Optional[str] = declaration + logger.info("found varname: " + declaration) + break + # Markdown case is special, because the stacktrace ends at + # https://github.com/widgetti/solara/blob/604d2e54146308d64a209334d0314d2baba75108/solara/components/markdown.py#L368 + elif file.endswith("components/markdown.py"): + self._varname = "markdown_content" + break + if not hasattr(self, "_varname"): + logger.info("No varname found") + self._varname = None @property def lock(self): @@ -130,7 +164,10 @@ def cleanup(): return cleanup def fire(self, new: T, old: T): - logger.info("value change from %s to %s, will fire events", old, new) + if settings.main.log_level in ["DEBUG", "INFO"] and self._varname is not None: + logger.info(f"value of {self._varname if self._varname is not None else ''} changed from %s to %s, will fire events", old, new) + else: + logger.info("value changed from %s to %s, will fire events", old, new) scope_id = self._get_scope_key() scopes = set() for listener, scope in self.listeners[scope_id].copy():