From 9243adee605a6306338eb58185416fd8a3745f75 Mon Sep 17 00:00:00 2001 From: Vysakh Sreenivasan Date: Sat, 10 Aug 2024 23:08:48 +0530 Subject: [PATCH] send more error context info, so it can be fixed --- src/drd/cli/commands.py | 8 +++-- src/drd/cli/monitor/error_resolver.py | 27 ++++++++------- src/drd/cli/monitor/output_monitor.py | 48 +++++++++++++++++++-------- src/drd/cli/monitor/server_monitor.py | 40 ++++++++++++++++++---- 4 files changed, 88 insertions(+), 35 deletions(-) diff --git a/src/drd/cli/commands.py b/src/drd/cli/commands.py index bf72888..0510a22 100644 --- a/src/drd/cli/commands.py +++ b/src/drd/cli/commands.py @@ -16,8 +16,12 @@ VERSION = "0.13.9" # Update this as you release new versions -logging.basicConfig(level=logging.INFO, - format='%(asctime)s - %(name)s - %(levelname)s - %(message)s') +logging.basicConfig(level=logging.DEBUG, + format='%(asctime)s - %(name)s - %(levelname)s - %(message)s', + filename='dravid_monitor.log', + filemode='a') + +# Also log to console def parse_multiline_input(input_string): diff --git a/src/drd/cli/monitor/error_resolver.py b/src/drd/cli/monitor/error_resolver.py index 53939fd..f7f1441 100644 --- a/src/drd/cli/monitor/error_resolver.py +++ b/src/drd/cli/monitor/error_resolver.py @@ -8,7 +8,6 @@ from ...utils.file_utils import get_file_content from ...utils.input import confirm_with_user import logging -import time def monitoring_handle_error_with_dravid(error, line, monitor): @@ -82,19 +81,19 @@ def monitoring_handle_error_with_dravid(error, line, monitor): print_success("Fix applied.") logger.info(f"User response to restart: ") - # if requires_restart: - # print_info("The applied fix requires a server restart.") - # restart_input = confirm_with_user( - # "Do you want to restart the server now? [y/N]: " - # ) - # if restart_input: - print_info("Requesting server restart...") - monitor.perform_restart() - # else: - # print_info( - # "Server restart postponed. You may need to restart manually if issues persist.") - # else: - # print_info("The applied fix does not require a server restart.") + if requires_restart: + print_info("The applied fix requires a server restart.") + restart_input = confirm_with_user( + "Do you want to restart the server now? [y/N]: " + ) + if restart_input: + print_info("Requesting server restart...") + monitor.perform_restart() + else: + print_info( + "Server restart postponed. You may need to restart manually if issues persist.") + else: + print_info("The applied fix does not require a server restart.") logger.info("Error handling completed") return True diff --git a/src/drd/cli/monitor/output_monitor.py b/src/drd/cli/monitor/output_monitor.py index 882ba47..abd464c 100644 --- a/src/drd/cli/monitor/output_monitor.py +++ b/src/drd/cli/monitor/output_monitor.py @@ -2,6 +2,7 @@ import select import time import threading +from collections import deque import re logger = logging.getLogger(__name__) @@ -14,6 +15,9 @@ def __init__(self, monitor): self.last_output_time = None self.idle_detected = threading.Event() self.stop_event = threading.Event() + self.buffer_size = 50 # Number of lines to keep in buffer + self.error_timeout = 2 + logger.info("OutputMonitor initialized") def start(self): self.stop_event.clear() @@ -27,9 +31,12 @@ def stop(self): self.thread.join(timeout=5) def _monitor_output(self): - error_buffer = [] + output_buffer = deque(maxlen=self.buffer_size) self.last_output_time = time.time() + error_detected = False + error_start_time = None + logger.info("Starting output monitoring") while not self.stop_event.is_set(): if self.monitor.process is None or self.monitor.process.poll() is not None: logger.info( @@ -45,32 +52,46 @@ def _monitor_output(self): if line: line = line.strip() print(line, flush=True) - logger.debug(f"Server output: {line}") - error_buffer.append(line) - if len(error_buffer) > 10: - error_buffer.pop(0) + output_buffer.append(line) + self.last_output_time = time.time() self.monitor.retry_count = 0 - if not self.monitor.processing_input.is_set(): - self._check_for_errors(line, error_buffer) + + if not error_detected: + error_detected = self._check_for_errors(line) + if error_detected: + error_start_time = time.time() + elif time.time() - error_start_time > self.error_timeout: + self._handle_error(list(output_buffer)) + error_detected = False + output_buffer.clear() else: self._check_idle_state() else: self._check_idle_state() + + if error_detected and time.time() - error_start_time > self.error_timeout: + self._handle_error(list(output_buffer)) + error_detected = False + output_buffer.clear() + except Exception as e: logger.error(f"Error in output monitoring: {str(e)}") time.sleep(1) # Prevent rapid error logging logger.info("Output monitoring stopped.") - def _check_for_errors(self, line, error_buffer): + def _check_for_errors(self, line): + logger.info(f"Checking for errors in line: {line}") for error_pattern in self.monitor.error_handlers.keys(): if re.search(error_pattern, line, re.IGNORECASE): - full_error = '\n'.join(error_buffer) - logger.error(f"Error detected: {full_error}") - self.monitor.handle_error(full_error) - error_buffer.clear() - break + return True + return False + + def _handle_error(self, error_context): + full_error = '\n'.join(error_context) + logger.error(f"Full error context:\n{full_error}") + self.monitor.handle_error(full_error) def _check_idle_state(self): current_time = time.time() @@ -78,3 +99,4 @@ def _check_idle_state(self): not self.monitor.error_handling_in_progress.is_set() and not self.monitor.processing_input.is_set()): self.idle_detected.set() + logger.info("Idle state detected") diff --git a/src/drd/cli/monitor/server_monitor.py b/src/drd/cli/monitor/server_monitor.py index ddd5e4a..fa2c5b6 100644 --- a/src/drd/cli/monitor/server_monitor.py +++ b/src/drd/cli/monitor/server_monitor.py @@ -4,7 +4,7 @@ from queue import Queue from .input_handler import InputHandler from .output_monitor import OutputMonitor -from ...utils import print_info, print_success, print_error, print_header, print_prompt +from ...utils import print_info, print_success, print_error, print_header, print_prompt, print_warning from ...metadata.project_metadata import ProjectMetadataManager import logging @@ -30,7 +30,11 @@ def __init__(self, project_dir: str, error_handlers: dict, command: str): self.error_handling_in_progress = threading.Event() self.error_handlers = { str(pattern): handler for pattern, handler in error_handlers.items() + } + self.error_handlers['default'] = self.default_error_handler + logger.info( + f"Initialized error handlers: {list(self.error_handlers.keys())}") def start(self): self.should_stop.clear() @@ -120,16 +124,40 @@ def _main_loop(self): finally: self.stop() - def handle_error(self, error_msg): + def handle_error(self, error_context): + logger.info("Entering handle_error method") self.error_handling_in_progress.set() self.output_monitor.idle_detected.clear() + + print_warning("An error has been detected. Here's the context:") + try: for pattern, handler in self.error_handlers.items(): - if re.search(pattern, error_msg, re.IGNORECASE): - handler(error_msg, self) + logger.info(f"Checking error pattern: {pattern}") + if re.search(pattern, error_context, re.IGNORECASE): + logger.info(f"Matched error pattern: {pattern}") + handler(error_context, self) break - finally: - self.error_handling_in_progress.clear() + else: + logger.warning( + "No specific handler found for this error. Using default error handler.") + print_warning( + "No specific handler found for this error. Using default error handler.") + self.error_handlers['default'](error_context, self) + except Exception as e: + logger.error(f"Error during error handling: {str(e)}") + print_error(f"Failed to handle the error: {str(e)}") + + self.error_handling_in_progress.clear() + logger.info("Exiting handle_error method") + + def default_error_handler(self, error_context, monitor): + logger.warning( + "Default error handler invoked. No specific fix available.") + print_warning( + "Default error handler invoked. No specific fix available.") + print_info( + "Please review the error and make necessary code changes manually.") def request_restart(self): self.restart_requested.set()