#!/usr/bin/env python3 """ Interactive debugging for StreamLens button issues Run this and interact with the live app while monitoring button states """ import sys import time import threading from pathlib import Path # Add analyzer to path sys.path.insert(0, str(Path(__file__).parent)) from analyzer.tui.textual.app_v2 import StreamLensAppV2 from analyzer.analysis.core import EthernetAnalyzer from textual_state_visualizer import TextualStateMonitor, TextualStateWebServer class InteractiveDebugger: """Interactive debugger that monitors button states in real-time""" def __init__(self): self.analyzer = None self.app = None self.monitor = None self.web_server = None self.monitoring = False def setup_analyzer_with_data(self): """Create analyzer with some sample data""" from analyzer.models.flow_stats import FlowStats, FrameTypeStats self.analyzer = EthernetAnalyzer() # Add sample flows to trigger button updates flow1 = FlowStats(src_ip="192.168.1.1", dst_ip="192.168.1.2") flow1.frame_types["CH10-Data"] = FrameTypeStats("CH10-Data", count=1500) flow1.frame_types["UDP"] = FrameTypeStats("UDP", count=800) self.analyzer.flows["flow1"] = flow1 flow2 = FlowStats(src_ip="192.168.1.3", dst_ip="192.168.1.4") flow2.frame_types["PTP-Sync"] = FrameTypeStats("PTP-Sync", count=600) flow2.frame_types["PTP-Signaling"] = FrameTypeStats("PTP-Signaling", count=300) self.analyzer.flows["flow2"] = flow2 print("๐Ÿ“Š Sample data added to analyzer:") print(" Flow 1: CH10-Data(1500), UDP(800)") print(" Flow 2: PTP-Sync(600), PTP-Signaling(300)") def start_debugging(self): """Start the app with full debugging enabled""" print("๐Ÿš€ Starting StreamLens with interactive debugging...") # Setup analyzer self.setup_analyzer_with_data() # Create app self.app = StreamLensAppV2(analyzer=self.analyzer) # Start state monitoring self.monitor = TextualStateMonitor(self.app) self.monitor.start_monitoring(interval=0.5) # Monitor every 500ms # Start web interface self.web_server = TextualStateWebServer(self.monitor, port=8080) self.web_server.start() print("๐ŸŒ Web debugging interface: http://localhost:8080") print("๐Ÿ“ฑ Starting StreamLens app...") print() print("๐Ÿ”ง DEBUGGING COMMANDS (while app is running):") print(" Ctrl+D,T - Print widget tree to console") print(" Ctrl+D,F - Show focused widget") print(" Ctrl+D,W - Start additional web debugger") print() print("๐Ÿงช INTERACTIVE TESTING:") print(" 1. Watch the web interface in your browser") print(" 2. Try loading a PCAP file in the app") print(" 3. Watch for button changes in real-time") print(" 4. Use keyboard shortcuts to debug instantly") print() print("๐Ÿ“Š The web interface will show:") print(" - Real-time widget tree") print(" - Button count and properties") print(" - State changes as they happen") print(" - Focus tracking") print() # Run the app try: self.app.run() except KeyboardInterrupt: print("\n๐Ÿ›‘ App stopped by user") finally: self.cleanup() def cleanup(self): """Clean up debugging resources""" print("\n๐Ÿงน Cleaning up debugging...") if self.monitor: self.monitor.stop_monitoring() if self.web_server: self.web_server.stop() def create_vscode_debug_config(): """Create VS Code debug configuration""" vscode_config = { "version": "0.2.0", "configurations": [ { "name": "Debug StreamLens Interactive", "type": "python", "request": "launch", "program": "${workspaceFolder}/interactive_debug.py", "console": "integratedTerminal", "justMyCode": False, "env": { "PYTHONPATH": "${workspaceFolder}" } }, { "name": "Debug StreamLens Button Issues", "type": "python", "request": "launch", "program": "${workspaceFolder}/debug_button_issues.py", "console": "integratedTerminal", "justMyCode": False, "env": { "PYTHONPATH": "${workspaceFolder}" } } ] } # Create .vscode directory if it doesn't exist vscode_dir = Path(".vscode") vscode_dir.mkdir(exist_ok=True) # Write launch.json import json launch_json = vscode_dir / "launch.json" with open(launch_json, 'w') as f: json.dump(vscode_config, f, indent=4) print(f"โœ… Created VS Code debug configuration: {launch_json}") def create_breakpoint_helper(): """Create a helper script with strategic breakpoints""" breakpoint_script = ''' # Add these breakpoints to key locations for debugging # 1. In filtered_flow_view.py - refresh_frame_types method def refresh_frame_types(self): """Update frame type button counts and reorder by count (highest to left)""" import pdb; pdb.set_trace() # BREAKPOINT: Start of refresh # Throttle button refresh to prevent race conditions import time current_time = time.time() if current_time - self._last_refresh_time < self._refresh_throttle_seconds: print(f"๐Ÿšซ Refresh throttled (last: {self._last_refresh_time}, current: {current_time})") return # Skip refresh if called too recently print(f"๐Ÿ”„ Starting refresh_frame_types at {current_time}") self._last_refresh_time = current_time # Get all detected frame types with their total packet counts frame_types = self._get_all_frame_types() print(f"๐Ÿ“Š Frame types found: {frame_types}") # If no frame types yet, skip button update if not frame_types: print("โš ๏ธ No frame types, skipping button update") return # BREAKPOINT: Before button removal/creation import pdb; pdb.set_trace() # Rest of method... # 2. In filtered_flow_view.py - compose method def compose(self): """Create the filter bar and flow grid""" import pdb; pdb.set_trace() # BREAKPOINT: Widget creation # Filter button bar at top with Horizontal(id="filter-bar"): # Overview button (hotkey 1) - compact format overview_btn = Button("1.Overview", id="btn-overview", classes="-active") self.frame_type_buttons["Overview"] = overview_btn print(f"โœ… Created overview button: {overview_btn}") yield overview_btn # Create predefined frame type buttons at initialization hotkeys = ['2', '3', '4', '5', '6', '7', '8', '9', '0'] for i, frame_type in enumerate(self.predefined_frame_types): if i < len(hotkeys): # Start with 0 count - will be updated during data refresh btn = FrameTypeButton(frame_type, hotkeys[i], 0) self.frame_type_buttons[frame_type] = btn print(f"โœ… Created predefined button {i+1}: {btn} for {frame_type}") yield btn # BREAKPOINT: After all buttons created import pdb; pdb.set_trace() # 3. Strategic print statements for tracking def debug_button_lifecycle(): """Add this to track button lifecycle""" def log_button_state(self, phase): print(f"\\n๐Ÿ” BUTTON STATE - {phase}:") print(f" Buttons dict: {len(self.frame_type_buttons)} entries") for name, btn in self.frame_type_buttons.items(): if hasattr(btn, 'parent'): parent_status = "has parent" if btn.parent else "NO PARENT" else: parent_status = "no parent attr" print(f" {name}: {btn} ({parent_status})") ''' with open("debugging_breakpoints.py", 'w') as f: f.write(breakpoint_script) print("โœ… Created debugging_breakpoints.py with strategic breakpoint locations") def main(): print("๐Ÿ”ง StreamLens Interactive Debugging Setup") print("=" * 60) # Create VS Code configuration create_vscode_debug_config() # Create breakpoint helper create_breakpoint_helper() print("\n๐ŸŽฏ RECOMMENDED DEBUGGING APPROACH:") print("\n1. **VS Code Debugging**:") print(" - Open this project in VS Code") print(" - Use F5 to start 'Debug StreamLens Interactive'") print(" - Set breakpoints in filtered_flow_view.py") print(" - Step through button creation/refresh logic") print("\n2. **Interactive Monitoring**:") print(" - Run: python interactive_debug.py") print(" - Open http://localhost:8080 in browser") print(" - Load a PCAP file and watch real-time changes") print("\n3. **Strategic Breakpoints**:") print(" - Add breakpoints at:") print(" โ€ข filtered_flow_view.py:142 (compose method)") print(" โ€ข filtered_flow_view.py:219 (refresh_frame_types method)") print(" โ€ข filtered_flow_view.py:171 (on_mount method)") print("\n4. **Live Console Debugging**:") print(" - While app runs, press Ctrl+D,T for widget tree") print(" - Check button parent relationships") print(" - Monitor refresh timing") print("\n๐Ÿ” KEY THINGS TO CHECK:") print(" โœ“ Are buttons created in compose()?") print(" โœ“ Do buttons have parents after creation?") print(" โœ“ What triggers refresh_frame_types()?") print(" โœ“ Are buttons removed during refresh?") print(" โœ“ What's the order of operations?") choice = input("\nโ“ Start interactive debugging now? (y/N): ").lower().strip() if choice in ['y', 'yes']: debugger = InteractiveDebugger() debugger.start_debugging() else: print("\n๐Ÿ“ Setup complete! Use VS Code or run interactive_debug.py when ready.") if __name__ == "__main__": main()