"""
Statistics and Monitoring Display Module
This module provides a visual dashboard for viewing application statistics,
performance metrics, and system information.
"""
import panel as pn
import param
from utils.app_context import AppContext
from utils.performance_monitor import performance_monitor
class StatsDisplay(param.Parameterized):
"""
Reactive statistics dashboard that displays real-time application metrics.
Uses Panel's param.depends to automatically update when state changes.
"""
# Refresh trigger
refresh_trigger = param.Integer(default=0)
def __init__(self, context: AppContext, **params):
super().__init__(**params)
self.context = context
@param.depends('refresh_trigger')
def _state_stats_panel(self):
"""Display state statistics (reactive to refresh trigger)."""
stats = self.context.state.get_stats()
html_content = f"""
State Statistics
| Event Lists: |
{self.context.state.event_data_count} |
| Light Curves: |
{self.context.state.light_curve_count} |
| Timeseries: |
{self.context.state.timeseries_count} |
| Total Additions: |
{stats.get('total_additions', 0)} |
| Total Removals: |
{stats.get('total_removals', 0)} |
| Evictions (LRU): |
{stats.get('total_evictions', 0)} |
| Last Operation: |
{self.context.state.last_operation or 'None'}
|
"""
return pn.pane.HTML(html_content, sizing_mode='stretch_width')
@param.depends('refresh_trigger')
def _memory_stats_panel(self):
"""Display memory statistics (reactive to refresh trigger)."""
mem_info = self.context.state.get_system_memory_info()
if not mem_info:
return pn.pane.Markdown("*Memory information unavailable*")
# Convert MB to GB
total_gb = mem_info.get('total_mb', 0) / 1024
available_gb = mem_info.get('available_mb', 0) / 1024
limit_gb = mem_info.get('allocated_limit_mb', 0) / 1024
app_usage_gb = self.context.state.memory_usage_mb / 1024
html_content = f"""
Memory Usage
| Total System RAM: |
{total_gb:.2f} GB |
| Available: |
{available_gb:.2f} GB |
| App Limit (80%): |
{limit_gb:.2f} GB |
| Current App Usage: |
{app_usage_gb:.3f} GB |
"""
return pn.pane.HTML(html_content, sizing_mode='stretch_width')
@param.depends('refresh_trigger')
def _performance_stats_panel(self):
"""Display performance statistics (reactive to refresh trigger)."""
summary = performance_monitor.get_summary()
html_content = f"""
Performance Metrics
| Total Operations: |
{summary.get('total_operations', 0)} |
| Unique Operations: |
{summary.get('unique_operations', 0)} |
| Avg Duration: |
{summary.get('avg_duration_ms', 0):.2f} ms |
| Success Rate: |
{summary.get('success_rate', 0):.1f}% |
| Most Frequent: |
{summary.get('most_frequent') or 'N/A'} |
| Slowest Operation: |
{summary.get('slowest') or 'N/A'}
|
"""
return pn.pane.HTML(html_content, sizing_mode='stretch_width')
@param.depends('refresh_trigger')
def _recent_operations_panel(self):
"""Display recent operations list (reactive to refresh trigger)."""
recent = performance_monitor.get_recent_operations(limit=10)
if not recent:
return pn.pane.Markdown("*No recent operations*")
rows = ""
for op in reversed(recent): # Most recent first
status_icon = "[OK]" if op.success else "[X]"
status_color = "#28a745" if op.success else "#dc3545"
time_str = op.start_time.strftime("%H:%M:%S")
rows += f"""
| {status_icon} |
{time_str} |
{op.operation_name} |
{op.duration_ms:.2f} ms |
"""
html_content = f"""
Recent Operations
| Status |
Time |
Operation |
Duration |
{rows}
"""
return pn.pane.HTML(html_content, sizing_mode='stretch_width')
def view(self):
"""Create the complete stats dashboard view."""
# Refresh button
refresh_button = pn.widgets.Button(
name="Refresh Stats",
button_type="primary",
width=200
)
def on_refresh(event):
self.refresh_trigger += 1
refresh_button.on_click(on_refresh)
# Create layout (no duplicate header - header is set in sidebar.py)
dashboard = pn.Column(
pn.Row(refresh_button, align='center'),
pn.layout.Divider(),
self._state_stats_panel,
self._memory_stats_panel,
self._performance_stats_panel,
self._recent_operations_panel,
sizing_mode='stretch_width'
)
return dashboard
def create_stats_dashboard(context: AppContext):
"""
Factory function to create the stats dashboard.
Args:
context: Application context
Returns:
Panel dashboard component
"""
stats_display = StatsDisplay(context)
return stats_display.view()