javitechjkd/backtestingv2
0
1"""2Dashboard de Monitoreo - Fase 53Visualización de logs y métricas en Streamlit4"""5 6import streamlit as st7from datetime import datetime, timedelta8import sys9from pathlib import Path10import json11 12# Add parent directory for imports13sys.path.insert(0, str(Path(__file__).parent.parent))14 15from backtesting_app.core.logger import get_logger, OperationType16 17 18def render_monitoring_dashboard():19 """Renderiza el dashboard de monitoreo"""20 21 st.markdown("## 📊 Dashboard de Monitoreo")22 st.write("Visualiza logs de operaciones y estadísticas de rendimiento en tiempo real")23 24 # Obtener logger25 logger = get_logger()26 27 # Tabs28 tab1, tab2, tab3 = st.tabs(["📈 Resumen Hoy", "📊 Estadísticas Globales", "📋 Logs Detallados"])29 30 with tab1:31 st.markdown("### Operaciones de Hoy")32 33 # Resumen general34 col1, col2, col3, col4 = st.columns(4)35 36 summary = logger.get_operations_summary()37 38 with col1:39 st.metric(40 "📊 Total Ops",41 summary['total_operations'],42 delta=None,43 label_visibility="visible"44 )45 46 with col2:47 st.metric(48 "✅ Exitosas",49 summary['successful'],50 delta=None,51 label_visibility="visible"52 )53 54 with col3:55 st.metric(56 "❌ Fallidas",57 summary['failed'],58 delta=None,59 label_visibility="visible"60 )61 62 with col4:63 if summary['total_operations'] > 0:64 success_rate = (summary['successful'] / summary['total_operations']) * 10065 st.metric(66 "📈 Tasa Éxito",67 f"{success_rate:.1f}%",68 delta=None,69 label_visibility="visible"70 )71 else:72 st.metric(73 "📈 Tasa Éxito",74 "N/A",75 delta=None,76 label_visibility="visible"77 )78 79 st.divider()80 81 # Desglose por tipo de operación82 st.markdown("### Por Tipo de Operación")83 84 # Obtener resumen por cada tipo85 op_summary = {}86 for op_type in OperationType:87 summary = logger.get_operations_summary(op_type)88 if summary['total_operations'] > 0:89 op_summary[op_type.value] = summary90 91 if op_summary:92 cols = st.columns(len(op_summary))93 94 for col, (op_type, summary) in zip(cols, op_summary.items()):95 with col:96 st.markdown(f"**{op_type}**")97 st.write(f"Total: {summary['total_operations']}")98 st.write(f"✅ {summary['successful']} exitosas")99 st.write(f"❌ {summary['failed']} fallidas")100 if summary['total_operations'] > 0:101 st.write(f"⏱️ {summary['avg_duration']:.2f}s promedio")102 else:103 st.info("No hay operaciones registradas hoy")104 105 with tab2:106 st.markdown("### Estadísticas Globales")107 108 stats = logger.get_performance_stats()109 110 if stats:111 st.markdown("#### Resumen por Tipo de Operación")112 113 # Tabla de estadísticas114 data = []115 for op_type, stat in stats.items():116 data.append({117 "Operación": op_type,118 "Cantidad": stat['count'],119 "Min (s)": f"{stat['min_duration']:.3f}",120 "Max (s)": f"{stat['max_duration']:.3f}",121 "Promedio (s)": f"{stat['avg_duration']:.3f}",122 "Éxito %": f"{stat['success_rate']:.1f}%"123 })124 125 st.dataframe(126 data,127 use_container_width=True,128 hide_index=True129 )130 else:131 st.info("No hay estadísticas disponibles")132 133 with tab3:134 st.markdown("### Logs Detallados")135 136 # Filtros137 col1, col2, col3 = st.columns(3)138 139 with col1:140 operation_filter = st.selectbox(141 "Filtrar por tipo de operación",142 options=["Todas"] + [op.value for op in OperationType],143 index=0144 )145 146 with col2:147 log_limit = st.slider(148 "Mostrar últimos N logs",149 min_value=5,150 max_value=100,151 value=20,152 step=5153 )154 155 with col3:156 st.empty()157 158 # Aplicar filtros159 filtered_logs = logger.json_logs[-log_limit:]160 161 if operation_filter != "Todas":162 filtered_logs = [163 log for log in filtered_logs164 if log.get('operation_type') == operation_filter165 ]166 167 if filtered_logs:168 # Mostrar logs en orden reverso (más recientes primero)169 for log in reversed(filtered_logs):170 timestamp = log.get('timestamp', 'N/A')171 op_type = log.get('operation_type', log.get('level', 'EVENT'))172 status = log.get('status', log.get('level', 'INFO'))173 174 # Emoji basado en el estado175 if status == 'success':176 emoji = "✅"177 elif status == 'error':178 emoji = "❌"179 else:180 emoji = "📝"181 182 # Expandible con detalles183 with st.expander(184 f"{emoji} {op_type} - {timestamp}",185 expanded=False186 ):187 st.json(log)188 else:189 st.info("No hay logs que coincidan con los filtros")190 191 # Limpieza de logs antiguos192 st.divider()193 st.markdown("### Mantenimiento")194 195 col1, col2 = st.columns(2)196 197 with col1:198 if st.button("🧹 Limpiar logs > 30 días", use_container_width=True):199 old_count = len(logger.json_logs)200 logger.clear_old_logs(days=30)201 new_count = len(logger.json_logs)202 deleted = old_count - new_count203 204 st.success(f"✅ Eliminados {deleted} logs antiguos")205 st.rerun()206 207 with col2:208 st.metric("📁 Total logs", len(logger.json_logs), label_visibility="visible")209 210 211if __name__ == "__main__":212 render_monitoring_dashboard()213 