Files
StreamLens/debug_with_prints.py

191 lines
8.9 KiB
Python

#!/usr/bin/env python3
"""
Add detailed logging to filtered_flow_view.py to trace button lifecycle
"""
import sys
from pathlib import Path
def add_debug_prints_to_filtered_flow_view():
"""Add comprehensive logging to track button issues"""
view_path = Path("analyzer/tui/textual/widgets/filtered_flow_view.py")
if not view_path.exists():
print("❌ filtered_flow_view.py not found")
return False
# Read current content
with open(view_path, 'r') as f:
content = f.read()
# Check if debug prints already added
if "🔍 DEBUG:" in content:
print("⚠️ Debug prints already added")
return True
# Create backup
backup_path = view_path.with_suffix('.py.debug_backup')
with open(backup_path, 'w') as f:
f.write(content)
print(f"📁 Backup created: {backup_path}")
# Add debug imports at the top
debug_imports = '''
import time
import traceback
def debug_log(message):
"""Debug logging with timestamp"""
timestamp = time.strftime("%H:%M:%S.%f")[:-3]
print(f"[{timestamp}] 🔍 DEBUG: {message}")
def debug_button_state(frame_type_buttons, phase):
"""Log current button state"""
debug_log(f"=== BUTTON STATE - {phase} ===")
debug_log(f"Total buttons in dict: {len(frame_type_buttons)}")
for name, btn in frame_type_buttons.items():
if hasattr(btn, 'parent') and btn.parent:
parent_info = f"parent: {btn.parent.__class__.__name__}"
else:
parent_info = "NO PARENT"
debug_log(f" {name}: {btn.__class__.__name__} ({parent_info})")
debug_log("=" * 40)
'''
# Insert debug imports after the existing imports
lines = content.split('\n')
insert_index = 0
# Find where to insert (after imports but before class definition)
for i, line in enumerate(lines):
if line.startswith('class FilteredFlowView'):
insert_index = i
break
# Insert debug functions
debug_lines = debug_imports.strip().split('\n')
for j, debug_line in enumerate(debug_lines):
lines.insert(insert_index + j, debug_line)
# Now add debug prints to key methods
# 1. Add to __init__
init_debug = ''' debug_log("FilteredFlowView.__init__ called")'''
# 2. Add to compose method
compose_debug = ''' debug_log("compose() - Creating filter bar and buttons")
debug_button_state(self.frame_type_buttons, "BEFORE_COMPOSE")'''
compose_end_debug = ''' debug_log("compose() - All widgets created")
debug_button_state(self.frame_type_buttons, "AFTER_COMPOSE")'''
# 3. Add to on_mount method
mount_debug = ''' debug_log("on_mount() - Initializing view")
debug_button_state(self.frame_type_buttons, "BEFORE_MOUNT_SETUP")'''
mount_end_debug = ''' debug_log("on_mount() - Initialization complete")
debug_button_state(self.frame_type_buttons, "AFTER_MOUNT_COMPLETE")'''
# 4. Add to refresh_frame_types method
refresh_start_debug = ''' debug_log("refresh_frame_types() - Starting refresh")
debug_button_state(self.frame_type_buttons, "BEFORE_REFRESH")
# Log throttling decision
import time
current_time = time.time()
debug_log(f"Refresh timing - current: {current_time}, last: {self._last_refresh_time}, throttle: {self._refresh_throttle_seconds}")'''
refresh_throttle_debug = ''' debug_log("refresh_frame_types() - THROTTLED, skipping refresh")
return # Skip refresh if called too recently'''
refresh_frame_types_debug = ''' debug_log(f"Frame types detected: {frame_types}")
# If no frame types yet, skip button update
if not frame_types:
debug_log("refresh_frame_types() - No frame types, skipping")
return'''
refresh_before_remove_debug = ''' debug_log("refresh_frame_types() - About to remove/recreate buttons")
debug_button_state(self.frame_type_buttons, "BEFORE_BUTTON_REMOVAL")'''
refresh_after_create_debug = ''' debug_log("refresh_frame_types() - Buttons recreated")
debug_button_state(self.frame_type_buttons, "AFTER_BUTTON_CREATION")'''
# Apply the debug additions
modified_content = '\n'.join(lines)
# Insert debug prints using string replacement
replacements = [
('def __init__(self, analyzer: \'EthernetAnalyzer\', **kwargs):\n super().__init__(**kwargs)',
'def __init__(self, analyzer: \'EthernetAnalyzer\', **kwargs):\n debug_log("FilteredFlowView.__init__ called")\n super().__init__(**kwargs)'),
('def compose(self):\n """Create the filter bar and flow grid"""',
'def compose(self):\n """Create the filter bar and flow grid"""\n debug_log("compose() - Creating filter bar and buttons")\n debug_button_state(self.frame_type_buttons, "BEFORE_COMPOSE")'),
('yield self.flow_table',
'yield self.flow_table\n debug_log("compose() - All widgets created")\n debug_button_state(self.frame_type_buttons, "AFTER_COMPOSE")'),
('def on_mount(self):\n """Initialize the view"""',
'def on_mount(self):\n """Initialize the view"""\n debug_log("on_mount() - Initializing view")\n debug_button_state(self.frame_type_buttons, "BEFORE_MOUNT_SETUP")'),
('self._update_button_highlighting()',
'self._update_button_highlighting()\n debug_log("on_mount() - Initialization complete")\n debug_button_state(self.frame_type_buttons, "AFTER_MOUNT_COMPLETE")'),
('def refresh_frame_types(self):\n """Update frame type button counts and reorder by count (highest to left)"""',
'def refresh_frame_types(self):\n """Update frame type button counts and reorder by count (highest to left)"""\n debug_log("refresh_frame_types() - Starting refresh")\n debug_button_state(self.frame_type_buttons, "BEFORE_REFRESH")'),
('if current_time - self._last_refresh_time < self._refresh_throttle_seconds:\n return # Skip refresh if called too recently',
'if current_time - self._last_refresh_time < self._refresh_throttle_seconds:\n debug_log("refresh_frame_types() - THROTTLED, skipping refresh")\n return # Skip refresh if called too recently'),
('# If no frame types yet, skip button update\n if not frame_types:\n return',
'# If no frame types yet, skip button update\n if not frame_types:\n debug_log("refresh_frame_types() - No frame types, skipping")\n return'),
('# Order changed, need to recreate buttons\n try:',
'# Order changed, need to recreate buttons\n debug_log("refresh_frame_types() - About to remove/recreate buttons")\n debug_button_state(self.frame_type_buttons, "BEFORE_BUTTON_REMOVAL")\n try:'),
('# Update button highlighting\n self._update_button_highlighting()',
'# Update button highlighting\n self._update_button_highlighting()\n debug_log("refresh_frame_types() - Buttons recreated")\n debug_button_state(self.frame_type_buttons, "AFTER_BUTTON_CREATION")')
]
for old, new in replacements:
if old in modified_content:
modified_content = modified_content.replace(old, new)
print(f"✅ Added debug to: {old.split('\\n')[0][:50]}...")
else:
print(f"⚠️ Could not find: {old.split('\\n')[0][:50]}...")
# Write the modified content
with open(view_path, 'w') as f:
f.write(modified_content)
print(f"✅ Debug prints added to {view_path}")
return True
def main():
print("🔧 Adding Debug Prints to Track Button Lifecycle")
print("=" * 60)
success = add_debug_prints_to_filtered_flow_view()
if success:
print("\n✅ Debug prints added successfully!")
print("\n🚀 Now run the app and watch the console output:")
print(" python debug_streamlens.py")
print("\n📊 You'll see detailed logs showing:")
print(" • When buttons are created")
print(" • When refresh_frame_types() is called")
print(" • Button parent relationships")
print(" • Throttling decisions")
print(" • Button removal/recreation")
print("\n🔍 Look for patterns like:")
print(" • Buttons created but losing parents")
print(" • Refresh called too frequently")
print(" • Button removal without recreation")
print("\n💡 To remove debug prints later:")
print(" • Restore from .debug_backup file")
else:
print("\n❌ Failed to add debug prints")
if __name__ == "__main__":
main()