From ab7b6bfc23f5fb95f1c6392a845469ce81de489f Mon Sep 17 00:00:00 2001 From: Dusan Omercevic Date: Thu, 19 Mar 2026 18:16:34 +0100 Subject: [PATCH 1/7] Removing things which are no longer needed on the client. --- plain2code.py | 12 ------------ pyproject.toml | 5 ----- 2 files changed, 17 deletions(-) diff --git a/plain2code.py b/plain2code.py index 420032a..7fb6bea 100644 --- a/plain2code.py +++ b/plain2code.py @@ -115,14 +115,7 @@ def setup_logging( ): # Set default level to INFO for everything not explicitly configured logging.getLogger().setLevel(logging.INFO) - logging.getLogger("urllib3").setLevel(logging.WARNING) - logging.getLogger("httpx").setLevel(logging.WARNING) - logging.getLogger("httpcore").setLevel(logging.WARNING) - logging.getLogger("anthropic").setLevel(logging.WARNING) - logging.getLogger("langsmith").setLevel(logging.WARNING) logging.getLogger("git").setLevel(logging.WARNING) - logging.getLogger("anthropic._base_client").setLevel(logging.WARNING) - logging.getLogger("services.langsmith.langsmith_service").setLevel(logging.WARNING) logging.getLogger("repositories").setLevel(logging.WARNING) logging.getLogger("transitions").setLevel(logging.ERROR) logging.getLogger("transitions.extensions.diagrams").setLevel(logging.ERROR) @@ -139,11 +132,6 @@ def setup_logging( except Exception as e: console.warning(f"Failed to load logging configuration from {args.logging_config_path}: {str(e)}") - # Allow detailed retry logs for anthropic if needed - logging.getLogger("anthropic._base_client").setLevel(logging.DEBUG) - if logging.getLogger("anthropic._base_client").level == logging.DEBUG: - logging.getLogger("anthropic._base_client").addFilter(RetryOnlyFilter()) - # The IndentedFormatter provides better multiline log readability. # We add the TuiLoggingHandler to the root logger. # CRITICAL: We must remove existing handlers (like StreamHandler) to prevent double-logging diff --git a/pyproject.toml b/pyproject.toml index 664ba4f..88ce9df 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -102,13 +102,8 @@ exclude = [ "^\\.venv/", "^\\.env/", "^\\.conda/", - "^build/", - "^dist/", "^tests/", "^examples/", - "^render_cache/", - "^src/services/langsmith/", - "^deploy/", ] [tool.pytest.ini_options] From e8bf3c8a17cf8f963f386b5564f95fa429f109bb Mon Sep 17 00:00:00 2001 From: Dusan Omercevic Date: Thu, 19 Mar 2026 18:16:57 +0100 Subject: [PATCH 2/7] Fixing a bug in handling --logging-config-path --- plain2code_arguments.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plain2code_arguments.py b/plain2code_arguments.py index de2b7b5..e40332c 100644 --- a/plain2code_arguments.py +++ b/plain2code_arguments.py @@ -328,7 +328,7 @@ def create_parser(): parser.add_argument( "--logging-config-path", - action="store_true", + type=str, default="logging_config.yaml", help="Path to the logging configuration file.", ) From edf4e4f577e63be0ab8fe45553d2f151ba2e8825 Mon Sep 17 00:00:00 2001 From: Dusan Omercevic Date: Thu, 19 Mar 2026 18:19:47 +0100 Subject: [PATCH 3/7] Proper set up of logging to work correctly with TUI also for logging level DEBUG. --- plain2code.py | 10 +++++++--- plain2code_console.py | 22 +++++++++++++--------- plain2code_events.py | 2 +- plain2code_logger.py | 4 +++- tui/components.py | 2 +- 5 files changed, 25 insertions(+), 15 deletions(-) diff --git a/plain2code.py b/plain2code.py index 7fb6bea..12c0d5a 100644 --- a/plain2code.py +++ b/plain2code.py @@ -43,6 +43,7 @@ TuiLoggingHandler, dump_crash_logs, get_log_file_path, + LOGGER_NAME, ) from plain2code_state import RunState from plain2code_utils import print_dry_run_output @@ -115,6 +116,7 @@ def setup_logging( ): # Set default level to INFO for everything not explicitly configured logging.getLogger().setLevel(logging.INFO) + logging.getLogger(LOGGER_NAME).setLevel(logging.INFO) logging.getLogger("git").setLevel(logging.WARNING) logging.getLogger("repositories").setLevel(logging.WARNING) logging.getLogger("transitions").setLevel(logging.ERROR) @@ -136,9 +138,9 @@ def setup_logging( # We add the TuiLoggingHandler to the root logger. # CRITICAL: We must remove existing handlers (like StreamHandler) to prevent double-logging # that spills into the TUI dashboard. - root_logger = logging.getLogger() - for h in root_logger.handlers[:]: - root_logger.removeHandler(h) + root_logger = logging.getLogger(LOGGER_NAME) + configured_log_level = root_logger.level + root_logger.setLevel(logging.DEBUG) # Capture all logs; handlers will filter levels as needed formatter = IndentedFormatter("%(levelname)s:%(name)s:%(message)s") @@ -151,6 +153,7 @@ def setup_logging( try: file_handler = logging.FileHandler(log_file_path, mode="w") file_handler.setFormatter(formatter) + file_handler.setLevel(configured_log_level) root_logger.addHandler(file_handler) except Exception as e: console.warning(f"Failed to setup file logging to {log_file_path}: {str(e)}") @@ -159,6 +162,7 @@ def setup_logging( # in case we need to dump them on crash. crash_handler = CrashLogHandler() crash_handler.setFormatter(formatter) + crash_handler.setLevel(configured_log_level) root_logger.addHandler(crash_handler) root_logger.info(f"Render ID: {render_id}") # Ensure render ID is logged in to codeplain.log file diff --git a/plain2code_console.py b/plain2code_console.py index 2f4d715..916a803 100644 --- a/plain2code_console.py +++ b/plain2code_console.py @@ -4,8 +4,12 @@ from rich.style import Style from rich.tree import Tree +import plain2code_logger + CHARACTERS_TO_TOKENS_RULE_OF_THUMB_RATIO = 4 +logger = logging.getLogger(plain2code_logger.LOGGER_NAME) + class Plain2CodeConsole(Console): INFO_STYLE = Style() @@ -22,35 +26,35 @@ def __init__(self): self.llm_encoding = tiktoken.get_encoding("cl100k_base") except Exception as e: - logging.warning( + logger.warning( "Failed to import optional library tiktoken. Using approximate instead of exact token count." ) - logging.debug(f"Exception: {e}") + logger.debug(f"Exception: {e}") self.llm_encoding = None def info(self, *args, **kwargs): - logging.info(" ".join(map(str, args))) + logger.info(" ".join(map(str, args))) super().print(*args, **kwargs, style=self.INFO_STYLE) def warning(self, *args, **kwargs): - logging.warning(" ".join(map(str, args))) + logger.warning(" ".join(map(str, args))) super().print(*args, **kwargs, style=self.WARNING_STYLE) def error(self, *args, **kwargs): - logging.error(" ".join(map(str, args))) + logger.error(" ".join(map(str, args))) super().print(*args, **kwargs, style=self.ERROR_STYLE) def input(self, *args, **kwargs): # We also log input as info so it shows in the toggled view - logging.info(" ".join(map(str, args))) + logger.info(" ".join(map(str, args))) super().print(*args, **kwargs, style=self.INPUT_STYLE) def output(self, *args, **kwargs): - logging.info(" ".join(map(str, args))) + logger.info(" ".join(map(str, args))) super().print(*args, **kwargs, style=self.OUTPUT_STYLE) def debug(self, *args, **kwargs): - logging.debug(" ".join(map(str, args))) + logger.debug(" ".join(map(str, args))) super().print(*args, **kwargs, style=self.DEBUG_STYLE) def print_list(self, items, style=None): @@ -116,7 +120,7 @@ def _count_tokens(self, text): def print_resources(self, resources_list, linked_resources): if len(resources_list) == 0: - self.input("Linked resources: None") + self.debug("Linked resources: None") return self.input("Linked resources:") diff --git a/plain2code_events.py b/plain2code_events.py index df39249..e957a8b 100644 --- a/plain2code_events.py +++ b/plain2code_events.py @@ -40,7 +40,7 @@ class RenderFailed(BaseEvent): @dataclass class LogMessageEmitted(BaseEvent): - logger_name: str # e.g., "services.langsmith.langsmith_service", "root" + logger_name: str # e.g., "codeplain" level: str # e.g., "INFO", "DEBUG", "ERROR" message: str # The actual log message timestamp: str # Formatted timestamp diff --git a/plain2code_logger.py b/plain2code_logger.py index 270cde9..7c71c5e 100644 --- a/plain2code_logger.py +++ b/plain2code_logger.py @@ -6,6 +6,8 @@ from event_bus import EventBus from plain2code_events import LogMessageEmitted +LOGGER_NAME = "codeplain" + class RetryOnlyFilter(logging.Filter): def filter(self, record): @@ -105,7 +107,7 @@ def dump_crash_logs(args, formatter=None): if formatter is None: formatter = IndentedFormatter("%(levelname)s:%(name)s:%(message)s") - root_logger = logging.getLogger() + root_logger = logging.getLogger(LOGGER_NAME) crash_handler = next((h for h in root_logger.handlers if isinstance(h, CrashLogHandler)), None) if crash_handler and args.filename: diff --git a/tui/components.py b/tui/components.py index 9eb947c..8c4493e 100644 --- a/tui/components.py +++ b/tui/components.py @@ -488,7 +488,7 @@ class StructuredLogView(VerticalScroll): def __init__(self, **kwargs): super().__init__(**kwargs) - self.min_level = "DEBUG" # Show all by default + self.min_level = "INFO" # By default, show INFO and above def _should_show_log(self, level: str) -> bool: """Check if log should be shown based on minimum level.""" From 077c3cf4941c32bc7e41c831f532ae1e96af0d8d Mon Sep 17 00:00:00 2001 From: Dusan Omercevic Date: Thu, 19 Mar 2026 18:24:46 +0100 Subject: [PATCH 4/7] Removed unused code. --- plain2code.py | 3 +-- plain2code_logger.py | 19 ------------------- 2 files changed, 1 insertion(+), 21 deletions(-) diff --git a/plain2code.py b/plain2code.py index 12c0d5a..ea386ae 100644 --- a/plain2code.py +++ b/plain2code.py @@ -37,13 +37,12 @@ PlainSyntaxError, ) from plain2code_logger import ( + LOGGER_NAME, CrashLogHandler, IndentedFormatter, - RetryOnlyFilter, TuiLoggingHandler, dump_crash_logs, get_log_file_path, - LOGGER_NAME, ) from plain2code_state import RunState from plain2code_utils import print_dry_run_output diff --git a/plain2code_logger.py b/plain2code_logger.py index 7c71c5e..7ee5deb 100644 --- a/plain2code_logger.py +++ b/plain2code_logger.py @@ -9,25 +9,6 @@ LOGGER_NAME = "codeplain" -class RetryOnlyFilter(logging.Filter): - def filter(self, record): - # Allow all logs with level > DEBUG (i.e., INFO and above) - if record.levelno > logging.DEBUG: - return True - # For DEBUG logs, only allow if message matches retry-related patterns - msg = record.getMessage().lower() - return ( - "retrying due to" in msg - or "raising timeout error" in msg - or "raising connection error" in msg - or "encountered exception" in msg - or "retrying request" in msg - or "retry left" in msg - or "1 retry left" in msg - or "retries left" in msg - ) - - class IndentedFormatter(logging.Formatter): def format(self, record): original_message = record.getMessage() From 6b0a495a881c041767d8be652f03cf51182dfbcb Mon Sep 17 00:00:00 2001 From: Dusan Omercevic Date: Thu, 19 Mar 2026 18:28:56 +0100 Subject: [PATCH 5/7] Removed a comment that is no longer valid. --- plain2code.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/plain2code.py b/plain2code.py index ea386ae..fc6ec67 100644 --- a/plain2code.py +++ b/plain2code.py @@ -135,8 +135,6 @@ def setup_logging( # The IndentedFormatter provides better multiline log readability. # We add the TuiLoggingHandler to the root logger. - # CRITICAL: We must remove existing handlers (like StreamHandler) to prevent double-logging - # that spills into the TUI dashboard. root_logger = logging.getLogger(LOGGER_NAME) configured_log_level = root_logger.level root_logger.setLevel(logging.DEBUG) # Capture all logs; handlers will filter levels as needed From 28535790f7b037b7c4b0f99c2b7f6ada10a7aae3 Mon Sep 17 00:00:00 2001 From: Dusan Omercevic Date: Thu, 19 Mar 2026 18:35:03 +0100 Subject: [PATCH 6/7] No need to output Render ID multiple times. --- plain2code.py | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/plain2code.py b/plain2code.py index fc6ec67..8207b42 100644 --- a/plain2code.py +++ b/plain2code.py @@ -110,7 +110,6 @@ def setup_logging( log_to_file: bool, log_file_name: str, plain_file_path: Optional[str], - render_id: str, headless: bool = False, ): # Set default level to INFO for everything not explicitly configured @@ -162,8 +161,6 @@ def setup_logging( crash_handler.setLevel(configured_log_level) root_logger.addHandler(crash_handler) - root_logger.info(f"Render ID: {render_id}") # Ensure render ID is logged in to codeplain.log file - def _check_connection(codeplainAPI: codeplain_api.CodeplainAPI): """Check API connectivity and validate API key and client version.""" @@ -282,9 +279,7 @@ def main(): # noqa: C901 # Suppress Rich console output. console.quiet = True - setup_logging( - args, event_bus, args.log_to_file, args.log_file_name, args.filename, run_state.render_id, args.headless - ) + setup_logging(args, event_bus, args.log_to_file, args.log_file_name, args.filename, args.headless) exc_info = None try: @@ -294,7 +289,7 @@ def main(): # noqa: C901 "API key is required. Please set the CODEPLAIN_API_KEY environment variable or provide it with the --api-key argument." ) - console.debug(f"Render ID: {run_state.render_id}") # Ensure render ID is logged to the console + console.info(f"Render ID: {run_state.render_id}") render(args, run_state, event_bus) except InvalidFridArgument as e: exc_info = sys.exc_info() From 21bec5e8c95d49919dfb700a9982010399323baf Mon Sep 17 00:00:00 2001 From: Dusan Omercevic Date: Fri, 20 Mar 2026 15:45:38 +0100 Subject: [PATCH 7/7] Removing unnecessary logger setting. --- plain2code.py | 1 - 1 file changed, 1 deletion(-) diff --git a/plain2code.py b/plain2code.py index 8207b42..4ca96fe 100644 --- a/plain2code.py +++ b/plain2code.py @@ -116,7 +116,6 @@ def setup_logging( logging.getLogger().setLevel(logging.INFO) logging.getLogger(LOGGER_NAME).setLevel(logging.INFO) logging.getLogger("git").setLevel(logging.WARNING) - logging.getLogger("repositories").setLevel(logging.WARNING) logging.getLogger("transitions").setLevel(logging.ERROR) logging.getLogger("transitions.extensions.diagrams").setLevel(logging.ERROR)