From be2df781cfd11aba89b013fbed604ea3e9afb95b Mon Sep 17 00:00:00 2001 From: Miguel Date: Sat, 16 Aug 2025 18:34:31 +0200 Subject: [PATCH] =?UTF-8?q?Implementaci=C3=B3n=20del=20sistema=20de=20moni?= =?UTF-8?q?toreo=20de=20rendimiento=20y=20gesti=C3=B3n=20de=20prioridades?= =?UTF-8?q?=20para=20el=20recording=20de=20PLC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Se creó el archivo PERFORMANCE_MONITORING.md que detalla el sistema de monitoreo de rendimiento en tiempo real, incluyendo métricas, logs y APIs de monitoreo. - Se desarrolló el archivo PRIORITY_SYSTEM.md que describe la arquitectura de prioridades para asegurar que el recording de CSV tenga máxima prioridad. - Se implementó el PerformanceMonitor en core/performance_monitor.py para registrar métricas de rendimiento, incluyendo tiempos de lectura, uso de CPU y errores. - Se creó el PriorityThreadManager en core/priority_manager.py para gestionar la prioridad de los hilos y asegurar que las operaciones de recording no sean interrumpidas. - Se implementó un sistema de logging rotativo en core/rotating_logger.py que permite la rotación automática de archivos de log y limpieza de archivos antiguos. --- PERFORMANCE_MONITORING.md | 235 + PRIORITY_SYSTEM.md | 191 + application_events.json | 7103 +++++++++++++++++++++++--- config/data/dataset_definitions.json | 2 +- core/performance_monitor.py | 395 ++ core/plc_data_streamer.py | 95 +- core/priority_manager.py | 342 ++ core/rotating_logger.py | 203 + core/streamer.py | 370 +- frontend/src/pages/Dashboard.jsx | 9 +- main.py | 139 +- system_state.json | 3 +- 12 files changed, 8157 insertions(+), 930 deletions(-) create mode 100644 PERFORMANCE_MONITORING.md create mode 100644 PRIORITY_SYSTEM.md create mode 100644 core/performance_monitor.py create mode 100644 core/priority_manager.py create mode 100644 core/rotating_logger.py diff --git a/PERFORMANCE_MONITORING.md b/PERFORMANCE_MONITORING.md new file mode 100644 index 0000000..3b2ea61 --- /dev/null +++ b/PERFORMANCE_MONITORING.md @@ -0,0 +1,235 @@ +# Sistema de Monitoreo de Rendimiento + +## 🔍 Objetivo + +Monitorear en **tiempo real** el rendimiento del sistema de recording, detectando automáticamente: +- **Puntos perdidos** por retrasos o errores de lectura +- **Estadísticas cada 10 segundos** con métricas detalladas +- **Tiempos de respuesta** de PLC, CSV y UDP +- **Uso de CPU** promedio +- **Errores** de lectura/escritura + +## 📊 Métricas Monitoreadas + +### 1. Estadísticas de Puntos +- **Points Saved**: Puntos guardados exitosamente en CSV +- **Points Lost**: Puntos perdidos por retrasos en el loop +- **Variables Saved**: Total de variables guardadas +- **UDP Points Sent**: Puntos enviados vía UDP streaming + +### 2. Timing y Performance +- **Read Time**: Tiempo de lectura del PLC por dataset +- **CSV Write Time**: Tiempo de escritura a archivo CSV +- **Loop Delay**: Retraso del loop vs. intervalo esperado +- **CPU Usage**: Uso promedio de CPU del proceso + +### 3. Errores y Fallos +- **Read Errors**: Errores de lectura del PLC +- **CSV Errors**: Errores de escritura CSV +- **UDP Errors**: Errores de transmisión UDP +- **Consecutive Errors**: Errores consecutivos por dataset + +## 🔥 Logs de Rendimiento + +### Log Principal (cada 10 segundos) +``` +📊 PERFORMANCE [2025-08-16 15:30:25] | Points: 120/10s (12.0/s) | Variables: 1800 | UDP: 80/10s | CPU: 15.3% | Delay: 0.002s±0.001s | Lost: 0 | Errors: R:0 C:0 U:0 +``` + +**Explicación**: +- `Points: 120/10s (12.0/s)`: 120 puntos guardados en 10s (12 puntos/segundo) +- `Variables: 1800`: Total de variables guardadas (120 puntos × 15 variables) +- `UDP: 80/10s`: 80 puntos enviados vía UDP +- `CPU: 15.3%`: Uso promedio de CPU del proceso +- `Delay: 0.002s±0.001s`: Retraso promedio ± desviación estándar +- `Lost: 0`: Puntos perdidos +- `Errors: R:0 C:0 U:0`: Errores de Read/CSV/UDP + +### Logs de Advertencia + +#### Puntos Perdidos +``` +⚠️ DATA LOSS: 3 points lost in last 10s (avg delay: 0.150s) +⚠️ POINTS LOST: Dataset 'Fast' - 2 points lost (expected: 0.100s, actual: 0.350s, delay: 0.150s) +``` + +#### Alto Uso de CPU +``` +⚠️ HIGH CPU: 85.5% average CPU usage +``` + +#### Errores de Lectura +``` +⚠️ READ ERRORS: 5 read errors in last 10s +``` + +#### Timing Overrun +``` +⏰ TIMING WARNING: Dataset 'Fast' loop overrun by 0.050s (read: 0.025s, csv: 0.020s, total: 0.150s) +``` + +## 🚨 Detección de Puntos Perdidos + +### Algoritmo de Detección +```python +# Detecta puntos perdidos cuando: +actual_interval = current_time - last_read_time +expected_interval = dataset_sampling_interval + +if actual_interval > expected_interval * 1.5: # 50% tolerancia + lost_points = int((actual_interval - expected_interval) / expected_interval) + # Log warning con detalles +``` + +### Ejemplo de Detección +``` +Dataset configurado: intervalo = 0.1s (10 puntos/segundo) +Lectura anterior: 15:30:25.000 +Lectura actual: 15:30:25.350 (retraso de 0.350s) + +Puntos perdidos = (0.350 - 0.100) / 0.100 = 2.5 → 2 puntos perdidos +``` + +## 📈 APIs de Monitoreo + +### `/api/performance/current` +Métricas actuales (ventana de 10s activa): +```json +{ + "success": true, + "current_performance": { + "points_saved": 45, + "points_rate": 12.5, + "variables_saved": 675, + "udp_points": 30, + "points_lost": 0, + "cpu_avg": 15.2, + "delay_avg": 0.002, + "read_errors": 0, + "csv_errors": 0, + "udp_errors": 0 + } +} +``` + +### `/api/performance/historical?windows=6` +Métricas históricas (últimos N×10s): +```json +{ + "success": true, + "historical_performance": { + "windows": 6, + "duration_minutes": 1.0, + "total_points_saved": 720, + "total_variables_saved": 10800, + "total_udp_sent": 480, + "total_points_lost": 0, + "total_errors": 0, + "points_per_second": 12.0, + "loss_rate_percent": 0.0, + "average_cpu_percent": 14.8, + "average_delay_seconds": 0.002 + } +} +``` + +### `/api/priority/status` +Incluye estadísticas de rendimiento completas: +```json +{ + "priority_protection": { + "performance_current": { ... }, + "performance_historical": { ... } + } +} +``` + +## 🔧 Configuración y Uso + +### Inicio Automático +El monitoreo se inicia automáticamente cuando: +```python +# Al iniciar CSV recording: +streamer.start_csv_recording() +# - Inicia PerformanceMonitor +# - Configura intervalos de datasets +# - Comienza logs cada 10s +``` + +### Configuración de Intervalos +```python +# Se configura automáticamente por dataset: +self.performance_monitor.set_dataset_interval(dataset_id, interval) +# Usado para detectar puntos perdidos +``` + +### Parada Automática +```python +# Al parar CSV recording: +streamer.stop_csv_recording() +# - Para PerformanceMonitor +# - Guarda estadísticas finales +``` + +## 📋 Interpretación de Métricas + +### ✅ Rendimiento Óptimo +- **Points Lost: 0** - Sin puntos perdidos +- **CPU < 50%** - Uso moderado de CPU +- **Delay < 10ms** - Timing dentro de tolerancia +- **Errors: 0** - Sin errores de lectura/escritura + +### ⚠️ Rendimiento Degradado +- **Points Lost > 0** - Revisar carga del sistema +- **CPU > 80%** - Optimizar configuración +- **Delay > 50ms** - Reducir frecuencia de muestreo +- **Errors > 0** - Verificar conexión PLC/archivos + +### 🚨 Problemas Críticos +- **Points Lost > 10% rate** - Sistema sobrecargado +- **CPU > 95%** - Recursos insuficientes +- **Consecutive Errors > 5** - Fallo de comunicación +- **Read Time > interval** - PLC sobrecargado + +## 🛠️ Troubleshooting + +### Alto Rate de Puntos Perdidos +1. **Reducir frecuencia** de muestreo de datasets +2. **Optimizar variables** - eliminar variables innecesarias +3. **Verificar carga** del sistema operativo +4. **Revisar conexión** PLC - latencia de red + +### CPU Elevado +1. **Verificar threads** activos en `/api/priority/status` +2. **Reducir datasets** simultáneos +3. **Optimizar hardware** - SSD, más RAM +4. **Cerrar aplicaciones** innecesarias + +### Errores de Lectura +1. **Verificar estado** PLC en `/api/status` +2. **Comprobar variables** - direcciones correctas +3. **Revisar red** - ping al PLC +4. **Verificar snap7.dll** disponible + +### Retrasos de CSV +1. **Verificar espacio** en disco +2. **Comprobar permisos** de escritura +3. **Optimizar directorio** records (SSD) +4. **Reducir tamaño** de archivos CSV + +## 📊 Métricas de Referencia + +### Sistema Típico (Fast=0.1s, DAR=1.0s) +- **Points/second**: 11-13 (Fast: 10/s + DAR: 1/s) +- **CPU Usage**: 10-25% (depende del hardware) +- **Read Time**: 5-15ms por dataset +- **CSV Write**: 1-5ms por punto +- **Delay**: < 10ms normalmente + +### Sistema Optimizado +- **Loss Rate**: < 0.1% +- **CPU Usage**: < 20% +- **Average Delay**: < 5ms +- **Error Rate**: 0 errors/10s + +La clave es mantener **Points Lost = 0** y **CPU < 50%** para garantizar recording continuo y confiable. diff --git a/PRIORITY_SYSTEM.md b/PRIORITY_SYSTEM.md new file mode 100644 index 0000000..31186a5 --- /dev/null +++ b/PRIORITY_SYSTEM.md @@ -0,0 +1,191 @@ +# Sistema de Prioridades para PLC Recording + +## 🔑 Objetivo Principal + +**El recording de CSV debe tener MÁXIMA PRIORIDAD** y nunca ser interrumpido por operaciones de API, procesamiento de gráficas, o cualquier otra tarea secundaria. + +## 🏗️ Arquitectura de Prioridades + +### Niveles de Prioridad + +``` +CRITICAL (10) 🔥 CSV Recording threads +HIGH (7) ⚡ PLC communication +NORMAL (5) 📡 UDP streaming, basic APIs +LOW (3) 📊 Historical data processing +BACKGROUND (1) 📈 Plot generation, file operations +``` + +### Componentes Implementados + +#### 1. `PriorityThreadManager` +- **Función**: Gestiona threads con diferentes prioridades +- **Ubicación**: `core/priority_manager.py` +- **Características**: + - Recording threads tienen prioridad CRITICAL + - API operations usan thread pools con prioridad NORMAL/LOW + - Background tasks (plots, cleanup) usan prioridad BACKGROUND + - Configuración automática de prioridades a nivel de OS (Windows/Linux) + +#### 2. `RecordingProtector` +- **Función**: Protege operaciones de recording mediante rate limiting +- **Características**: + - Limita APIs a máximo 10 requests/segundo cuando recording está activo + - Previene sobrecarga del sistema durante recording crítico + - Monitorea y reporta métricas de protección + +#### 3. Thread Separation +- **Recording Threads**: Ejecutan SOLO operaciones de CSV +- **API Thread Pool**: Maneja requests HTTP con prioridad más baja +- **Background Thread Pool**: Procesa tareas no críticas + +## 🔥 Protecciones Implementadas + +### 1. Recording Thread Protection +```python +# Los threads de recording tienen: +- Prioridad CRITICAL (máxima disponible en el OS) +- No son daemon threads (no se terminan automáticamente) +- Shutdown controlado y seguro +- Separación completa de operaciones UDP/API +``` + +### 2. API Rate Limiting +```python +# Protección contra sobrecarga de APIs: +- Máximo 10 requests/segundo durante recording +- Timeout de 2 segundos para operaciones de cache +- Rate limiting automático con respuestas HTTP 429 +``` + +### 3. Background Processing +```python +# Operaciones no críticas se ejecutan en background: +- UDP streaming a PlotJuggler +- Actualización de gráficas en tiempo real +- Cleanup de archivos CSV +- Procesamiento de datos históricos +``` + +## 📊 Monitoreo y Métricas + +### Endpoint de Status: `/api/priority/status` +```json +{ + "success": true, + "priority_protection": { + "csv_recording_enabled": true, + "priority_stats": { + "active_recording_threads": 2, + "recording_thread_names": ["Fast:recording_fast", "DAR:recording_dar"], + "api_pool_active": 2, + "background_pool_active": 1 + }, + "recording_protection": { + "recording_protection_active": true, + "api_requests_this_second": 3, + "api_rate_limit": 10, + "time_until_reset": 0.7 + } + } +} +``` + +### Logs de Prioridad +``` +🔥 CRITICAL PRIORITY: Dataset 'Fast' recording loop started (interval: 0.1s) +🔥 [2025-08-16 15:30:25.123] RECORDING Dataset 'Fast': 15 vars recorded +📡 Background: UDP sent 8 vars for dataset 'Fast' +📈 Background: Plot data updated for session abc123 +``` + +## 🛡️ Garantías de Protección + +### 1. Recording Never Stops +- **Thread isolation**: Recording threads completamente separados +- **OS Priority**: Máxima prioridad a nivel de sistema operativo +- **Resource protection**: Rate limiting de APIs para evitar competencia + +### 2. Graceful Degradation +- **API timeout**: APIs responden con error si exceden tiempo límite +- **Rate limiting**: APIs se limitan automáticamente durante recording +- **Background processing**: Tareas no críticas se postergan + +### 3. System Monitoring +- **Real-time stats**: Métricas en tiempo real de threads y protección +- **Logging detallado**: Logs específicos para operaciones críticas +- **Health checks**: Endpoints para verificar estado del sistema + +## 🚀 Uso en Producción + +### Configuración Automática +```python +# El sistema se configura automáticamente al inicializar: +streamer = PLCDataStreamer() +# - PriorityThreadManager configurado +# - RecordingProtector activado +# - Thread pools separados creados +# - Prioridades de OS configuradas +``` + +### APIs Protegidas +```python +# Estas APIs ahora usan protección de prioridad: +GET /api/datasets/{id}/variables/values # Rate limited +POST /api/csv/cleanup # Background processing +GET /api/priority/status # Monitoring +``` + +### Shutdown Seguro +```python +# Shutdown respeta prioridades: +1. Para CSV recording gracefully +2. Para UDP streaming +3. Espera threads de recording (timeout 10s) +4. Cierra thread pools de API/background +5. Limpia recursos +``` + +## 📋 Checklist de Funcionamiento + +### ✅ Recording Protection Active +- [ ] CSV recording threads tienen prioridad CRITICAL +- [ ] APIs limitadas a 10 req/s durante recording +- [ ] Background tasks no bloquean recording +- [ ] Logs muestran "🔥 CRITICAL PRIORITY" + +### ✅ System Health +- [ ] `/api/priority/status` responde correctamente +- [ ] Recording threads aparecen en stats +- [ ] Rate limiting funciona (HTTP 429 cuando excede) +- [ ] Background tasks se ejecutan sin bloquear + +### ✅ Performance Monitoring +- [ ] Recording intervals se mantienen estables +- [ ] No hay errores de timeout en recording +- [ ] APIs responden dentro de 2 segundos +- [ ] Cleanup se ejecuta en background + +## 🔧 Troubleshooting + +### Recording Lento +1. Verificar `/api/priority/status` - ¿threads críticos activos? +2. Revisar logs - ¿aparecen mensajes "🔥 CRITICAL"? +3. Comprobar rate limiting - ¿muchas APIs simultáneas? + +### APIs Lentas +1. Verificar rate limiting en `/api/priority/status` +2. Reducir frecuencia de requests de frontend +3. Usar cache del browser para datos estáticos + +### Threads Bloqueados +1. Revisar stats de thread pools +2. Verificar que recording threads no sean daemon +3. Comprobar shutdown order en logs + +## 📚 Referencias + +- `core/priority_manager.py`: Implementación completa del sistema +- `core/streamer.py`: Integration con DataStreamer +- `main.py`: APIs protegidas con rate limiting +- `application_events.json`: Logs de eventos de prioridad diff --git a/application_events.json b/application_events.json index 44bdd26..4e71aa7 100644 --- a/application_events.json +++ b/application_events.json @@ -1,807 +1,5 @@ { "events": [ - { - "timestamp": "2025-08-14T17:38:05.807687", - "level": "info", - "event_type": "application_started", - "message": "Application initialization completed successfully", - "details": {} - }, - { - "timestamp": "2025-08-14T17:38:05.874790", - "level": "info", - "event_type": "dataset_activated", - "message": "Dataset activated: DAR", - "details": { - "dataset_id": "DAR", - "variables_count": 2, - "streaming_count": 2, - "prefix": "gateway_phoenix" - } - }, - { - "timestamp": "2025-08-14T17:38:05.876790", - "level": "info", - "event_type": "dataset_activated", - "message": "Dataset activated: Fast", - "details": { - "dataset_id": "Fast", - "variables_count": 1, - "streaming_count": 0, - "prefix": "fast" - } - }, - { - "timestamp": "2025-08-14T17:38:05.878790", - "level": "info", - "event_type": "csv_recording_started", - "message": "CSV recording started: 2 datasets activated", - "details": { - "activated_datasets": 2, - "total_datasets": 3 - } - }, - { - "timestamp": "2025-08-14T17:38:05.923117", - "level": "error", - "event_type": "csv_cleanup_failed", - "message": "CSV cleanup failed: 'max_hours'", - "details": {} - }, - { - "timestamp": "2025-08-14T17:38:05.939112", - "level": "error", - "event_type": "csv_cleanup_failed", - "message": "CSV cleanup failed: 'max_hours'", - "details": {} - }, - { - "timestamp": "2025-08-14T17:39:08.007789", - "level": "info", - "event_type": "application_started", - "message": "Application initialization completed successfully", - "details": {} - }, - { - "timestamp": "2025-08-14T17:39:08.058547", - "level": "info", - "event_type": "dataset_activated", - "message": "Dataset activated: DAR", - "details": { - "dataset_id": "DAR", - "variables_count": 2, - "streaming_count": 2, - "prefix": "gateway_phoenix" - } - }, - { - "timestamp": "2025-08-14T17:39:08.060547", - "level": "info", - "event_type": "dataset_activated", - "message": "Dataset activated: Fast", - "details": { - "dataset_id": "Fast", - "variables_count": 1, - "streaming_count": 0, - "prefix": "fast" - } - }, - { - "timestamp": "2025-08-14T17:39:08.061549", - "level": "info", - "event_type": "csv_recording_started", - "message": "CSV recording started: 2 datasets activated", - "details": { - "activated_datasets": 2, - "total_datasets": 3 - } - }, - { - "timestamp": "2025-08-14T17:39:08.124019", - "level": "error", - "event_type": "csv_cleanup_failed", - "message": "CSV cleanup failed: 'max_hours'", - "details": {} - }, - { - "timestamp": "2025-08-14T17:39:08.138006", - "level": "error", - "event_type": "csv_cleanup_failed", - "message": "CSV cleanup failed: 'max_hours'", - "details": {} - }, - { - "timestamp": "2025-08-14T17:39:22.743912", - "level": "info", - "event_type": "application_started", - "message": "Application initialization completed successfully", - "details": {} - }, - { - "timestamp": "2025-08-14T17:39:22.793500", - "level": "info", - "event_type": "dataset_activated", - "message": "Dataset activated: DAR", - "details": { - "dataset_id": "DAR", - "variables_count": 2, - "streaming_count": 2, - "prefix": "gateway_phoenix" - } - }, - { - "timestamp": "2025-08-14T17:39:22.795500", - "level": "info", - "event_type": "dataset_activated", - "message": "Dataset activated: Fast", - "details": { - "dataset_id": "Fast", - "variables_count": 1, - "streaming_count": 0, - "prefix": "fast" - } - }, - { - "timestamp": "2025-08-14T17:39:22.796499", - "level": "info", - "event_type": "csv_recording_started", - "message": "CSV recording started: 2 datasets activated", - "details": { - "activated_datasets": 2, - "total_datasets": 3 - } - }, - { - "timestamp": "2025-08-14T17:39:22.826633", - "level": "error", - "event_type": "csv_cleanup_failed", - "message": "CSV cleanup failed: 'max_hours'", - "details": {} - }, - { - "timestamp": "2025-08-14T17:39:22.841933", - "level": "error", - "event_type": "csv_cleanup_failed", - "message": "CSV cleanup failed: 'max_hours'", - "details": {} - }, - { - "timestamp": "2025-08-14T17:43:30.822632", - "level": "info", - "event_type": "application_started", - "message": "Application initialization completed successfully", - "details": {} - }, - { - "timestamp": "2025-08-14T17:43:30.889374", - "level": "info", - "event_type": "dataset_activated", - "message": "Dataset activated: DAR", - "details": { - "dataset_id": "DAR", - "variables_count": 2, - "streaming_count": 2, - "prefix": "gateway_phoenix" - } - }, - { - "timestamp": "2025-08-14T17:43:30.891647", - "level": "info", - "event_type": "dataset_activated", - "message": "Dataset activated: Fast", - "details": { - "dataset_id": "Fast", - "variables_count": 2, - "streaming_count": 0, - "prefix": "fast" - } - }, - { - "timestamp": "2025-08-14T17:43:30.893648", - "level": "info", - "event_type": "csv_recording_started", - "message": "CSV recording started: 2 datasets activated", - "details": { - "activated_datasets": 2, - "total_datasets": 3 - } - }, - { - "timestamp": "2025-08-14T17:43:30.920591", - "level": "error", - "event_type": "csv_cleanup_failed", - "message": "CSV cleanup failed: 'max_hours'", - "details": {} - }, - { - "timestamp": "2025-08-14T17:43:30.935592", - "level": "error", - "event_type": "csv_cleanup_failed", - "message": "CSV cleanup failed: 'max_hours'", - "details": {} - }, - { - "timestamp": "2025-08-14T17:44:33.660715", - "level": "info", - "event_type": "application_started", - "message": "Application initialization completed successfully", - "details": {} - }, - { - "timestamp": "2025-08-14T17:44:33.727994", - "level": "info", - "event_type": "dataset_activated", - "message": "Dataset activated: DAR", - "details": { - "dataset_id": "DAR", - "variables_count": 2, - "streaming_count": 2, - "prefix": "gateway_phoenix" - } - }, - { - "timestamp": "2025-08-14T17:44:33.730995", - "level": "info", - "event_type": "dataset_activated", - "message": "Dataset activated: Fast", - "details": { - "dataset_id": "Fast", - "variables_count": 2, - "streaming_count": 0, - "prefix": "fast" - } - }, - { - "timestamp": "2025-08-14T17:44:33.733995", - "level": "info", - "event_type": "csv_recording_started", - "message": "CSV recording started: 2 datasets activated", - "details": { - "activated_datasets": 2, - "total_datasets": 3 - } - }, - { - "timestamp": "2025-08-14T17:44:33.759815", - "level": "error", - "event_type": "csv_cleanup_failed", - "message": "CSV cleanup failed: 'max_hours'", - "details": {} - }, - { - "timestamp": "2025-08-14T17:44:33.776813", - "level": "error", - "event_type": "csv_cleanup_failed", - "message": "CSV cleanup failed: 'max_hours'", - "details": {} - }, - { - "timestamp": "2025-08-14T17:47:31.993226", - "level": "info", - "event_type": "application_started", - "message": "Application initialization completed successfully", - "details": {} - }, - { - "timestamp": "2025-08-14T17:47:32.057893", - "level": "info", - "event_type": "dataset_activated", - "message": "Dataset activated: DAR", - "details": { - "dataset_id": "DAR", - "variables_count": 2, - "streaming_count": 2, - "prefix": "gateway_phoenix" - } - }, - { - "timestamp": "2025-08-14T17:47:32.060405", - "level": "info", - "event_type": "dataset_activated", - "message": "Dataset activated: Fast", - "details": { - "dataset_id": "Fast", - "variables_count": 2, - "streaming_count": 0, - "prefix": "fast" - } - }, - { - "timestamp": "2025-08-14T17:47:32.061404", - "level": "info", - "event_type": "csv_recording_started", - "message": "CSV recording started: 2 datasets activated", - "details": { - "activated_datasets": 2, - "total_datasets": 3 - } - }, - { - "timestamp": "2025-08-14T17:47:32.091335", - "level": "error", - "event_type": "csv_cleanup_failed", - "message": "CSV cleanup failed: 'max_hours'", - "details": {} - }, - { - "timestamp": "2025-08-14T17:47:32.154901", - "level": "error", - "event_type": "csv_cleanup_failed", - "message": "CSV cleanup failed: 'max_hours'", - "details": {} - }, - { - "timestamp": "2025-08-14T17:48:59.071337", - "level": "info", - "event_type": "application_started", - "message": "Application initialization completed successfully", - "details": {} - }, - { - "timestamp": "2025-08-14T17:48:59.123397", - "level": "info", - "event_type": "dataset_activated", - "message": "Dataset activated: DAR", - "details": { - "dataset_id": "DAR", - "variables_count": 2, - "streaming_count": 2, - "prefix": "gateway_phoenix" - } - }, - { - "timestamp": "2025-08-14T17:48:59.126395", - "level": "info", - "event_type": "dataset_activated", - "message": "Dataset activated: Fast", - "details": { - "dataset_id": "Fast", - "variables_count": 2, - "streaming_count": 0, - "prefix": "fast" - } - }, - { - "timestamp": "2025-08-14T17:48:59.128395", - "level": "info", - "event_type": "csv_recording_started", - "message": "CSV recording started: 2 datasets activated", - "details": { - "activated_datasets": 2, - "total_datasets": 3 - } - }, - { - "timestamp": "2025-08-14T17:48:59.173315", - "level": "error", - "event_type": "csv_cleanup_failed", - "message": "CSV cleanup failed: 'max_hours'", - "details": {} - }, - { - "timestamp": "2025-08-14T17:48:59.216717", - "level": "error", - "event_type": "csv_cleanup_failed", - "message": "CSV cleanup failed: 'max_hours'", - "details": {} - }, - { - "timestamp": "2025-08-14T17:49:02.129179", - "level": "info", - "event_type": "csv_recording_stopped", - "message": "CSV recording stopped (dataset threads continue for UDP streaming)", - "details": {} - }, - { - "timestamp": "2025-08-14T17:49:02.134181", - "level": "info", - "event_type": "udp_streaming_stopped", - "message": "UDP streaming to PlotJuggler stopped (CSV recording continues)", - "details": {} - }, - { - "timestamp": "2025-08-14T17:49:02.634246", - "level": "info", - "event_type": "dataset_deactivated", - "message": "Dataset deactivated: DAR", - "details": { - "dataset_id": "DAR" - } - }, - { - "timestamp": "2025-08-14T17:49:02.637375", - "level": "info", - "event_type": "dataset_deactivated", - "message": "Dataset deactivated: test", - "details": { - "dataset_id": "Test" - } - }, - { - "timestamp": "2025-08-14T17:49:02.858924", - "level": "info", - "event_type": "dataset_deactivated", - "message": "Dataset deactivated: Fast", - "details": { - "dataset_id": "Fast" - } - }, - { - "timestamp": "2025-08-14T17:49:02.862459", - "level": "info", - "event_type": "plc_disconnection", - "message": "Disconnected from PLC 10.1.33.11 (stopped recording and streaming)", - "details": {} - }, - { - "timestamp": "2025-08-14T17:49:53.651639", - "level": "info", - "event_type": "dataset_activated", - "message": "Dataset activated: DAR", - "details": { - "dataset_id": "DAR", - "variables_count": 2, - "streaming_count": 2, - "prefix": "gateway_phoenix" - } - }, - { - "timestamp": "2025-08-14T17:49:53.655650", - "level": "info", - "event_type": "dataset_activated", - "message": "Dataset activated: Fast", - "details": { - "dataset_id": "Fast", - "variables_count": 2, - "streaming_count": 0, - "prefix": "fast" - } - }, - { - "timestamp": "2025-08-14T17:49:53.657649", - "level": "info", - "event_type": "csv_recording_started", - "message": "CSV recording started: 2 datasets activated", - "details": { - "activated_datasets": 2, - "total_datasets": 3 - } - }, - { - "timestamp": "2025-08-14T17:49:53.661654", - "level": "info", - "event_type": "plc_connection", - "message": "Successfully connected to PLC 10.1.33.11 and auto-started CSV recording for 2 datasets", - "details": { - "ip": "10.1.33.11", - "rack": 0, - "slot": 2, - "symbols_path": "C:/Users/migue/Downloads/symSAE452.asc", - "auto_started_recording": true, - "recording_datasets": 2, - "dataset_names": [ - "DAR", - "Fast" - ] - } - }, - { - "timestamp": "2025-08-14T17:49:53.772728", - "level": "error", - "event_type": "csv_cleanup_failed", - "message": "CSV cleanup failed: 'max_hours'", - "details": {} - }, - { - "timestamp": "2025-08-14T17:49:53.851046", - "level": "error", - "event_type": "csv_cleanup_failed", - "message": "CSV cleanup failed: 'max_hours'", - "details": {} - }, - { - "timestamp": "2025-08-14T17:54:16.562817", - "level": "info", - "event_type": "csv_recording_stopped", - "message": "CSV recording stopped (dataset threads continue for UDP streaming)", - "details": {} - }, - { - "timestamp": "2025-08-14T17:54:16.565673", - "level": "info", - "event_type": "udp_streaming_stopped", - "message": "UDP streaming to PlotJuggler stopped (CSV recording continues)", - "details": {} - }, - { - "timestamp": "2025-08-14T17:54:16.611836", - "level": "info", - "event_type": "dataset_deactivated", - "message": "Dataset deactivated: DAR", - "details": { - "dataset_id": "DAR" - } - }, - { - "timestamp": "2025-08-14T17:54:17.041436", - "level": "info", - "event_type": "dataset_deactivated", - "message": "Dataset deactivated: Fast", - "details": { - "dataset_id": "Fast" - } - }, - { - "timestamp": "2025-08-14T17:54:17.043542", - "level": "info", - "event_type": "plc_disconnection", - "message": "Disconnected from PLC 10.1.33.11 (stopped recording and streaming)", - "details": {} - }, - { - "timestamp": "2025-08-14T17:54:19.910751", - "level": "info", - "event_type": "dataset_activated", - "message": "Dataset activated: DAR", - "details": { - "dataset_id": "DAR", - "variables_count": 2, - "streaming_count": 2, - "prefix": "gateway_phoenix" - } - }, - { - "timestamp": "2025-08-14T17:54:19.915265", - "level": "info", - "event_type": "dataset_activated", - "message": "Dataset activated: Fast", - "details": { - "dataset_id": "Fast", - "variables_count": 2, - "streaming_count": 0, - "prefix": "fast" - } - }, - { - "timestamp": "2025-08-14T17:54:19.917272", - "level": "info", - "event_type": "csv_recording_started", - "message": "CSV recording started: 2 datasets activated", - "details": { - "activated_datasets": 2, - "total_datasets": 3 - } - }, - { - "timestamp": "2025-08-14T17:54:19.920275", - "level": "info", - "event_type": "plc_connection", - "message": "Successfully connected to PLC 10.1.33.11 and auto-started CSV recording for 2 datasets", - "details": { - "ip": "10.1.33.11", - "rack": 0, - "slot": 2, - "symbols_path": "C:/Users/migue/Downloads/symSAE452.asc", - "auto_started_recording": true, - "recording_datasets": 2, - "dataset_names": [ - "DAR", - "Fast" - ] - } - }, - { - "timestamp": "2025-08-14T17:54:20.066169", - "level": "error", - "event_type": "csv_cleanup_failed", - "message": "CSV cleanup failed: 'max_hours'", - "details": {} - }, - { - "timestamp": "2025-08-14T17:54:20.236650", - "level": "error", - "event_type": "csv_cleanup_failed", - "message": "CSV cleanup failed: 'max_hours'", - "details": {} - }, - { - "timestamp": "2025-08-14T17:54:28.115437", - "level": "info", - "event_type": "application_started", - "message": "Application initialization completed successfully", - "details": {} - }, - { - "timestamp": "2025-08-14T17:54:28.213550", - "level": "info", - "event_type": "dataset_activated", - "message": "Dataset activated: DAR", - "details": { - "dataset_id": "DAR", - "variables_count": 2, - "streaming_count": 2, - "prefix": "gateway_phoenix" - } - }, - { - "timestamp": "2025-08-14T17:54:28.215746", - "level": "info", - "event_type": "dataset_activated", - "message": "Dataset activated: Fast", - "details": { - "dataset_id": "Fast", - "variables_count": 1, - "streaming_count": 0, - "prefix": "fast" - } - }, - { - "timestamp": "2025-08-14T17:54:28.217262", - "level": "info", - "event_type": "csv_recording_started", - "message": "CSV recording started: 2 datasets activated", - "details": { - "activated_datasets": 2, - "total_datasets": 3 - } - }, - { - "timestamp": "2025-08-14T17:54:28.320035", - "level": "error", - "event_type": "csv_cleanup_failed", - "message": "CSV cleanup failed: 'max_hours'", - "details": {} - }, - { - "timestamp": "2025-08-14T17:54:28.365636", - "level": "error", - "event_type": "csv_cleanup_failed", - "message": "CSV cleanup failed: 'max_hours'", - "details": {} - }, - { - "timestamp": "2025-08-14T18:00:00.091904", - "level": "error", - "event_type": "csv_cleanup_failed", - "message": "CSV cleanup failed: 'max_hours'", - "details": {} - }, - { - "timestamp": "2025-08-14T18:00:00.508749", - "level": "error", - "event_type": "csv_cleanup_failed", - "message": "CSV cleanup failed: 'max_hours'", - "details": {} - }, - { - "timestamp": "2025-08-14T18:02:22.596812", - "level": "info", - "event_type": "application_started", - "message": "Application initialization completed successfully", - "details": {} - }, - { - "timestamp": "2025-08-14T18:02:22.691257", - "level": "info", - "event_type": "dataset_activated", - "message": "Dataset activated: DAR", - "details": { - "dataset_id": "DAR", - "variables_count": 2, - "streaming_count": 2, - "prefix": "gateway_phoenix" - } - }, - { - "timestamp": "2025-08-14T18:02:22.693258", - "level": "info", - "event_type": "dataset_activated", - "message": "Dataset activated: Fast", - "details": { - "dataset_id": "Fast", - "variables_count": 1, - "streaming_count": 0, - "prefix": "fast" - } - }, - { - "timestamp": "2025-08-14T18:02:22.694257", - "level": "info", - "event_type": "csv_recording_started", - "message": "CSV recording started: 2 datasets activated", - "details": { - "activated_datasets": 2, - "total_datasets": 3 - } - }, - { - "timestamp": "2025-08-14T18:02:22.801349", - "level": "error", - "event_type": "csv_cleanup_failed", - "message": "CSV cleanup failed: 'max_hours'", - "details": {} - }, - { - "timestamp": "2025-08-14T18:02:22.847745", - "level": "error", - "event_type": "csv_cleanup_failed", - "message": "CSV cleanup failed: 'max_hours'", - "details": {} - }, - { - "timestamp": "2025-08-14T18:03:16.983216", - "level": "info", - "event_type": "application_started", - "message": "Application initialization completed successfully", - "details": {} - }, - { - "timestamp": "2025-08-14T18:03:17.079669", - "level": "info", - "event_type": "dataset_activated", - "message": "Dataset activated: DAR", - "details": { - "dataset_id": "DAR", - "variables_count": 2, - "streaming_count": 2, - "prefix": "gateway_phoenix" - } - }, - { - "timestamp": "2025-08-14T18:03:17.081681", - "level": "info", - "event_type": "dataset_activated", - "message": "Dataset activated: Fast", - "details": { - "dataset_id": "Fast", - "variables_count": 1, - "streaming_count": 0, - "prefix": "fast" - } - }, - { - "timestamp": "2025-08-14T18:03:17.082690", - "level": "info", - "event_type": "csv_recording_started", - "message": "CSV recording started: 2 datasets activated", - "details": { - "activated_datasets": 2, - "total_datasets": 3 - } - }, - { - "timestamp": "2025-08-14T18:03:17.159774", - "level": "error", - "event_type": "csv_cleanup_failed", - "message": "CSV cleanup failed: 'max_hours'", - "details": {} - }, - { - "timestamp": "2025-08-14T18:03:17.236154", - "level": "error", - "event_type": "csv_cleanup_failed", - "message": "CSV cleanup failed: 'max_hours'", - "details": {} - }, - { - "timestamp": "2025-08-14T18:03:33.688457", - "level": "info", - "event_type": "application_started", - "message": "Application initialization completed successfully", - "details": {} - }, - { - "timestamp": "2025-08-14T18:03:33.799243", - "level": "info", - "event_type": "dataset_activated", - "message": "Dataset activated: DAR", - "details": { - "dataset_id": "DAR", - "variables_count": 2, - "streaming_count": 2, - "prefix": "gateway_phoenix" - } - }, { "timestamp": "2025-08-14T18:03:33.802690", "level": "info", @@ -8792,8 +7990,6305 @@ "activated_datasets": 2, "total_datasets": 3 } + }, + { + "timestamp": "2025-08-16T17:35:28.089114", + "level": "info", + "event_type": "application_started", + "message": "Application initialization completed successfully", + "details": {} + }, + { + "timestamp": "2025-08-16T17:35:28.138633", + "level": "info", + "event_type": "dataset_activated", + "message": "Dataset activated: DAR", + "details": { + "dataset_id": "DAR", + "variables_count": 2, + "streaming_count": 2, + "prefix": "gateway_phoenix" + } + }, + { + "timestamp": "2025-08-16T17:35:28.151745", + "level": "info", + "event_type": "dataset_activated", + "message": "Dataset activated: Fast", + "details": { + "dataset_id": "Fast", + "variables_count": 2, + "streaming_count": 2, + "prefix": "fast" + } + }, + { + "timestamp": "2025-08-16T17:35:28.160963", + "level": "info", + "event_type": "csv_recording_started", + "message": "🔥 CRITICAL PRIORITY: CSV recording started with MAXIMUM PRIORITY and performance monitoring: 2 datasets activated", + "details": { + "activated_datasets": 2, + "total_datasets": 3, + "priority": "CRITICAL", + "recording_protection": true, + "performance_monitoring": true + } + }, + { + "timestamp": "2025-08-16T17:35:38.139460", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 36 points saved, 0 lost, 0.0% CPU", + "details": { + "duration": 11.065707445144653, + "points_saved": 36, + "points_rate": 3.2532940328000333, + "variables_saved": 72, + "udp_points_sent": 0, + "points_lost": 0, + "cpu_average": 0.0, + "cpu_max": 0.0, + "delay_average": 0.0, + "delay_max": 0.0, + "read_errors": 0, + "csv_errors": 0, + "udp_errors": 0, + "read_time_avg": 0.03419050243165758, + "csv_write_time_avg": 5.533960130479601e-05 + } + }, + { + "timestamp": "2025-08-16T17:35:48.151054", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 37 points saved, 0 lost, 0.0% CPU", + "details": { + "duration": 10.011594295501709, + "points_saved": 37, + "points_rate": 3.6957150787287096, + "variables_saved": 74, + "udp_points_sent": 0, + "points_lost": 0, + "cpu_average": 0.0, + "cpu_max": 0.0, + "delay_average": 0.0, + "delay_max": 0.0, + "read_errors": 0, + "csv_errors": 0, + "udp_errors": 0, + "read_time_avg": 0.03422231931944151, + "csv_write_time_avg": 0.0 + } + }, + { + "timestamp": "2025-08-16T17:35:58.161743", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 36 points saved, 0 lost, 0.0% CPU", + "details": { + "duration": 10.010688781738281, + "points_saved": 36, + "points_rate": 3.5961561471845966, + "variables_saved": 72, + "udp_points_sent": 0, + "points_lost": 0, + "cpu_average": 0.0, + "cpu_max": 0.0, + "delay_average": 0.0, + "delay_max": 0.0, + "read_errors": 0, + "csv_errors": 0, + "udp_errors": 0, + "read_time_avg": 0.03590715593761868, + "csv_write_time_avg": 0.0 + } + }, + { + "timestamp": "2025-08-16T17:36:08.175560", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 36 points saved, 0 lost, 1.7% CPU", + "details": { + "duration": 10.013817548751831, + "points_saved": 36, + "points_rate": 3.5950325462527735, + "variables_saved": 72, + "udp_points_sent": 0, + "points_lost": 0, + "cpu_average": 1.7, + "cpu_max": 1.7, + "delay_average": 0.0, + "delay_max": 0.0, + "read_errors": 0, + "csv_errors": 0, + "udp_errors": 0, + "read_time_avg": 0.03828871912426419, + "csv_write_time_avg": 0.0 + } + }, + { + "timestamp": "2025-08-16T17:36:18.187820", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 36 points saved, 0 lost, 0.0% CPU", + "details": { + "duration": 10.01226019859314, + "points_saved": 36, + "points_rate": 3.5955917331291984, + "variables_saved": 72, + "udp_points_sent": 0, + "points_lost": 0, + "cpu_average": 0.0, + "cpu_max": 0.0, + "delay_average": 0.0, + "delay_max": 0.0, + "read_errors": 0, + "csv_errors": 0, + "udp_errors": 0, + "read_time_avg": 0.03697745667563544, + "csv_write_time_avg": 0.0 + } + }, + { + "timestamp": "2025-08-16T17:36:28.199541", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 36 points saved, 0 lost, 0.0% CPU", + "details": { + "duration": 10.011720180511475, + "points_saved": 36, + "points_rate": 3.5957856742816845, + "variables_saved": 72, + "udp_points_sent": 0, + "points_lost": 0, + "cpu_average": 0.0, + "cpu_max": 0.0, + "delay_average": 0.0, + "delay_max": 0.0, + "read_errors": 0, + "csv_errors": 0, + "udp_errors": 0, + "read_time_avg": 0.038205709722306996, + "csv_write_time_avg": 0.0 + } + }, + { + "timestamp": "2025-08-16T17:36:38.210388", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 36 points saved, 0 lost, 0.0% CPU", + "details": { + "duration": 10.010847330093384, + "points_saved": 36, + "points_rate": 3.596099192501039, + "variables_saved": 72, + "udp_points_sent": 0, + "points_lost": 0, + "cpu_average": 0.0, + "cpu_max": 0.0, + "delay_average": 0.0, + "delay_max": 0.0, + "read_errors": 0, + "csv_errors": 0, + "udp_errors": 0, + "read_time_avg": 0.03884846634334988, + "csv_write_time_avg": 0.0 + } + }, + { + "timestamp": "2025-08-16T17:36:48.221667", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 36 points saved, 0 lost, 0.0% CPU", + "details": { + "duration": 10.011279344558716, + "points_saved": 36, + "points_rate": 3.5959440108487786, + "variables_saved": 72, + "udp_points_sent": 0, + "points_lost": 0, + "cpu_average": 0.0, + "cpu_max": 0.0, + "delay_average": 0.0, + "delay_max": 0.0, + "read_errors": 0, + "csv_errors": 0, + "udp_errors": 0, + "read_time_avg": 0.04061386320326063, + "csv_write_time_avg": 0.0 + } + }, + { + "timestamp": "2025-08-16T17:36:58.232210", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 36 points saved, 0 lost, 0.0% CPU", + "details": { + "duration": 10.010542869567871, + "points_saved": 36, + "points_rate": 3.59620856421686, + "variables_saved": 72, + "udp_points_sent": 0, + "points_lost": 0, + "cpu_average": 0.0, + "cpu_max": 0.0, + "delay_average": 0.0, + "delay_max": 0.0, + "read_errors": 0, + "csv_errors": 0, + "udp_errors": 0, + "read_time_avg": 0.04232892062928942, + "csv_write_time_avg": 0.0 + } + }, + { + "timestamp": "2025-08-16T17:37:08.243356", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 37 points saved, 0 lost, 0.0% CPU", + "details": { + "duration": 10.011146068572998, + "points_saved": 37, + "points_rate": 3.695880546199445, + "variables_saved": 74, + "udp_points_sent": 0, + "points_lost": 0, + "cpu_average": 0.0, + "cpu_max": 0.0, + "delay_average": 0.0, + "delay_max": 0.0, + "read_errors": 0, + "csv_errors": 0, + "udp_errors": 0, + "read_time_avg": 0.03578216320759541, + "csv_write_time_avg": 0.0 + } + }, + { + "timestamp": "2025-08-16T17:37:18.255815", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 36 points saved, 0 lost, 0.0% CPU", + "details": { + "duration": 10.012458324432373, + "points_saved": 36, + "points_rate": 3.5955205838063664, + "variables_saved": 72, + "udp_points_sent": 0, + "points_lost": 0, + "cpu_average": 0.0, + "cpu_max": 0.0, + "delay_average": 0.0, + "delay_max": 0.0, + "read_errors": 0, + "csv_errors": 0, + "udp_errors": 0, + "read_time_avg": 0.04042544629838732, + "csv_write_time_avg": 0.0 + } + }, + { + "timestamp": "2025-08-16T17:37:28.267047", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 36 points saved, 0 lost, 0.0% CPU", + "details": { + "duration": 10.011232376098633, + "points_saved": 36, + "points_rate": 3.5959608814943085, + "variables_saved": 72, + "udp_points_sent": 0, + "points_lost": 0, + "cpu_average": 0.0, + "cpu_max": 0.0, + "delay_average": 0.0, + "delay_max": 0.0, + "read_errors": 0, + "csv_errors": 0, + "udp_errors": 0, + "read_time_avg": 0.040577590465545654, + "csv_write_time_avg": 0.0 + } + }, + { + "timestamp": "2025-08-16T17:37:38.277538", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 36 points saved, 0 lost, 0.0% CPU", + "details": { + "duration": 10.010490894317627, + "points_saved": 36, + "points_rate": 3.5962272360124823, + "variables_saved": 72, + "udp_points_sent": 0, + "points_lost": 0, + "cpu_average": 0.0, + "cpu_max": 0.0, + "delay_average": 0.0, + "delay_max": 0.0, + "read_errors": 0, + "csv_errors": 0, + "udp_errors": 0, + "read_time_avg": 0.04081398910946316, + "csv_write_time_avg": 0.0 + } + }, + { + "timestamp": "2025-08-16T17:37:48.288422", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 36 points saved, 0 lost, 0.0% CPU", + "details": { + "duration": 10.010884523391724, + "points_saved": 36, + "points_rate": 3.596085831964334, + "variables_saved": 72, + "udp_points_sent": 0, + "points_lost": 0, + "cpu_average": 0.0, + "cpu_max": 0.0, + "delay_average": 0.0, + "delay_max": 0.0, + "read_errors": 0, + "csv_errors": 0, + "udp_errors": 0, + "read_time_avg": 0.03936559624142117, + "csv_write_time_avg": 0.0 + } + }, + { + "timestamp": "2025-08-16T17:37:58.299601", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 36 points saved, 0 lost, 0.0% CPU", + "details": { + "duration": 10.011178493499756, + "points_saved": 36, + "points_rate": 3.5959802358308512, + "variables_saved": 72, + "udp_points_sent": 0, + "points_lost": 0, + "cpu_average": 0.0, + "cpu_max": 0.0, + "delay_average": 0.0, + "delay_max": 0.0, + "read_errors": 0, + "csv_errors": 0, + "udp_errors": 0, + "read_time_avg": 0.04036520587073432, + "csv_write_time_avg": 0.0 + } + }, + { + "timestamp": "2025-08-16T17:38:08.311357", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 36 points saved, 0 lost, 0.2% CPU", + "details": { + "duration": 10.011756181716919, + "points_saved": 36, + "points_rate": 3.59577274422062, + "variables_saved": 72, + "udp_points_sent": 0, + "points_lost": 0, + "cpu_average": 0.2, + "cpu_max": 0.2, + "delay_average": 0.0, + "delay_max": 0.0, + "read_errors": 0, + "csv_errors": 0, + "udp_errors": 0, + "read_time_avg": 0.04146779245800442, + "csv_write_time_avg": 0.0 + } + }, + { + "timestamp": "2025-08-16T17:38:18.321766", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 36 points saved, 0 lost, 0.0% CPU", + "details": { + "duration": 10.010409355163574, + "points_saved": 36, + "points_rate": 3.5962565288531843, + "variables_saved": 72, + "udp_points_sent": 0, + "points_lost": 0, + "cpu_average": 0.0, + "cpu_max": 0.0, + "delay_average": 0.0, + "delay_max": 0.0, + "read_errors": 0, + "csv_errors": 0, + "udp_errors": 0, + "read_time_avg": 0.052210370699564614, + "csv_write_time_avg": 0.0 + } + }, + { + "timestamp": "2025-08-16T17:38:28.337728", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 37 points saved, 0 lost, 0.5% CPU", + "details": { + "duration": 10.015961170196533, + "points_saved": 37, + "points_rate": 3.694103778087429, + "variables_saved": 74, + "udp_points_sent": 0, + "points_lost": 0, + "cpu_average": 0.5, + "cpu_max": 0.5, + "delay_average": 0.0, + "delay_max": 0.0, + "read_errors": 0, + "csv_errors": 0, + "udp_errors": 0, + "read_time_avg": 0.040692754693933436, + "csv_write_time_avg": 0.0 + } + }, + { + "timestamp": "2025-08-16T17:38:38.348447", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 36 points saved, 0 lost, 0.2% CPU", + "details": { + "duration": 10.010719776153564, + "points_saved": 36, + "points_rate": 3.5961450130444406, + "variables_saved": 72, + "udp_points_sent": 0, + "points_lost": 0, + "cpu_average": 0.2, + "cpu_max": 0.2, + "delay_average": 0.0, + "delay_max": 0.0, + "read_errors": 0, + "csv_errors": 0, + "udp_errors": 0, + "read_time_avg": 0.03889468643400404, + "csv_write_time_avg": 0.0 + } + }, + { + "timestamp": "2025-08-16T17:38:48.359434", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 36 points saved, 0 lost, 0.0% CPU", + "details": { + "duration": 10.010986804962158, + "points_saved": 36, + "points_rate": 3.596049091000283, + "variables_saved": 72, + "udp_points_sent": 0, + "points_lost": 0, + "cpu_average": 0.0, + "cpu_max": 0.0, + "delay_average": 0.0, + "delay_max": 0.0, + "read_errors": 0, + "csv_errors": 0, + "udp_errors": 0, + "read_time_avg": 0.038851632012261286, + "csv_write_time_avg": 0.0 + } + }, + { + "timestamp": "2025-08-16T17:38:58.370422", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 36 points saved, 0 lost, 0.0% CPU", + "details": { + "duration": 10.010987758636475, + "points_saved": 36, + "points_rate": 3.5960487484307246, + "variables_saved": 72, + "udp_points_sent": 0, + "points_lost": 0, + "cpu_average": 0.0, + "cpu_max": 0.0, + "delay_average": 0.0, + "delay_max": 0.0, + "read_errors": 0, + "csv_errors": 0, + "udp_errors": 0, + "read_time_avg": 0.038373463683658175, + "csv_write_time_avg": 0.0 + } + }, + { + "timestamp": "2025-08-16T17:39:08.382534", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 36 points saved, 0 lost, 0.0% CPU", + "details": { + "duration": 10.01211166381836, + "points_saved": 36, + "points_rate": 3.5956450755634637, + "variables_saved": 72, + "udp_points_sent": 0, + "points_lost": 0, + "cpu_average": 0.0, + "cpu_max": 0.0, + "delay_average": 0.0, + "delay_max": 0.0, + "read_errors": 0, + "csv_errors": 0, + "udp_errors": 0, + "read_time_avg": 0.039986749490102134, + "csv_write_time_avg": 2.6490953233506944e-06 + } + }, + { + "timestamp": "2025-08-16T17:39:18.392873", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 36 points saved, 0 lost, 0.0% CPU", + "details": { + "duration": 10.010339260101318, + "points_saved": 36, + "points_rate": 3.596281710799443, + "variables_saved": 72, + "udp_points_sent": 0, + "points_lost": 0, + "cpu_average": 0.0, + "cpu_max": 0.0, + "delay_average": 0.0, + "delay_max": 0.0, + "read_errors": 0, + "csv_errors": 0, + "udp_errors": 0, + "read_time_avg": 0.04344462686114841, + "csv_write_time_avg": 0.0 + } + }, + { + "timestamp": "2025-08-16T17:39:28.404058", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 36 points saved, 0 lost, 0.0% CPU", + "details": { + "duration": 10.011184930801392, + "points_saved": 36, + "points_rate": 3.595977923576147, + "variables_saved": 72, + "udp_points_sent": 0, + "points_lost": 0, + "cpu_average": 0.0, + "cpu_max": 0.0, + "delay_average": 0.0, + "delay_max": 0.0, + "read_errors": 0, + "csv_errors": 0, + "udp_errors": 0, + "read_time_avg": 0.04024439387851291, + "csv_write_time_avg": 0.0 + } + }, + { + "timestamp": "2025-08-16T17:39:38.415625", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 36 points saved, 0 lost, 0.0% CPU", + "details": { + "duration": 10.01156759262085, + "points_saved": 36, + "points_rate": 3.5958404782218367, + "variables_saved": 72, + "udp_points_sent": 0, + "points_lost": 0, + "cpu_average": 0.0, + "cpu_max": 0.0, + "delay_average": 0.0, + "delay_max": 0.0, + "read_errors": 0, + "csv_errors": 0, + "udp_errors": 0, + "read_time_avg": 0.04137457741631402, + "csv_write_time_avg": 0.0 + } + }, + { + "timestamp": "2025-08-16T17:40:04.532147", + "level": "info", + "event_type": "application_started", + "message": "Application initialization completed successfully", + "details": {} + }, + { + "timestamp": "2025-08-16T17:40:04.580490", + "level": "info", + "event_type": "dataset_activated", + "message": "Dataset activated: DAR", + "details": { + "dataset_id": "DAR", + "variables_count": 2, + "streaming_count": 2, + "prefix": "gateway_phoenix" + } + }, + { + "timestamp": "2025-08-16T17:40:04.590492", + "level": "info", + "event_type": "dataset_activated", + "message": "Dataset activated: Fast", + "details": { + "dataset_id": "Fast", + "variables_count": 2, + "streaming_count": 2, + "prefix": "fast" + } + }, + { + "timestamp": "2025-08-16T17:40:04.602119", + "level": "info", + "event_type": "csv_recording_started", + "message": "🔥 CRITICAL PRIORITY: CSV recording started with MAXIMUM PRIORITY and performance monitoring: 2 datasets activated", + "details": { + "activated_datasets": 2, + "total_datasets": 3, + "priority": "CRITICAL", + "recording_protection": true, + "performance_monitoring": true + } + }, + { + "timestamp": "2025-08-16T17:40:14.580775", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 37 points saved, 0 lost, 0.0% CPU", + "details": { + "duration": 11.069085359573364, + "points_saved": 37, + "points_rate": 3.342642937340768, + "variables_saved": 74, + "udp_points_sent": 0, + "points_lost": 0, + "cpu_average": 0.0, + "cpu_max": 0.0, + "delay_average": 0.0, + "delay_max": 0.0, + "read_errors": 0, + "csv_errors": 0, + "udp_errors": 0, + "read_time_avg": 0.03904216998332256, + "csv_write_time_avg": 0.0001490760493922878 + } + }, + { + "timestamp": "2025-08-16T17:40:24.592459", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 36 points saved, 0 lost, 0.0% CPU", + "details": { + "duration": 10.011683940887451, + "points_saved": 36, + "points_rate": 3.5957986900662093, + "variables_saved": 72, + "udp_points_sent": 0, + "points_lost": 0, + "cpu_average": 0.0, + "cpu_max": 0.0, + "delay_average": 0.0, + "delay_max": 0.0, + "read_errors": 0, + "csv_errors": 0, + "udp_errors": 0, + "read_time_avg": 0.04174877537621392, + "csv_write_time_avg": 0.0 + } + }, + { + "timestamp": "2025-08-16T17:40:34.604293", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 36 points saved, 0 lost, 0.3% CPU", + "details": { + "duration": 10.011833667755127, + "points_saved": 36, + "points_rate": 3.595744914934448, + "variables_saved": 72, + "udp_points_sent": 0, + "points_lost": 0, + "cpu_average": 0.3, + "cpu_max": 0.3, + "delay_average": 0.0, + "delay_max": 0.0, + "read_errors": 0, + "csv_errors": 0, + "udp_errors": 0, + "read_time_avg": 0.03770591815312704, + "csv_write_time_avg": 0.0 + } + }, + { + "timestamp": "2025-08-16T17:40:44.615595", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 36 points saved, 0 lost, 0.0% CPU", + "details": { + "duration": 10.01130223274231, + "points_saved": 36, + "points_rate": 3.595935789677866, + "variables_saved": 72, + "udp_points_sent": 0, + "points_lost": 0, + "cpu_average": 0.0, + "cpu_max": 0.0, + "delay_average": 0.0, + "delay_max": 0.0, + "read_errors": 0, + "csv_errors": 0, + "udp_errors": 0, + "read_time_avg": 0.03750785854127672, + "csv_write_time_avg": 0.0 + } + }, + { + "timestamp": "2025-08-16T17:40:54.626486", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 36 points saved, 0 lost, 0.0% CPU", + "details": { + "duration": 10.01089072227478, + "points_saved": 36, + "points_rate": 3.596083605217868, + "variables_saved": 72, + "udp_points_sent": 0, + "points_lost": 0, + "cpu_average": 0.0, + "cpu_max": 0.0, + "delay_average": 0.0, + "delay_max": 0.0, + "read_errors": 0, + "csv_errors": 0, + "udp_errors": 0, + "read_time_avg": 0.041134370697869196, + "csv_write_time_avg": 0.0 + } + }, + { + "timestamp": "2025-08-16T17:41:04.638306", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 36 points saved, 0 lost, 0.0% CPU", + "details": { + "duration": 10.011820077896118, + "points_saved": 36, + "points_rate": 3.5957497957319497, + "variables_saved": 72, + "udp_points_sent": 0, + "points_lost": 0, + "cpu_average": 0.0, + "cpu_max": 0.0, + "delay_average": 0.0, + "delay_max": 0.0, + "read_errors": 0, + "csv_errors": 0, + "udp_errors": 0, + "read_time_avg": 0.04233575529522366, + "csv_write_time_avg": 0.0 + } + }, + { + "timestamp": "2025-08-16T17:41:14.649538", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 36 points saved, 0 lost, 0.0% CPU", + "details": { + "duration": 10.011232137680054, + "points_saved": 36, + "points_rate": 3.595960967132507, + "variables_saved": 72, + "udp_points_sent": 0, + "points_lost": 0, + "cpu_average": 0.0, + "cpu_max": 0.0, + "delay_average": 0.0, + "delay_max": 0.0, + "read_errors": 0, + "csv_errors": 0, + "udp_errors": 0, + "read_time_avg": 0.039648844136132136, + "csv_write_time_avg": 2.3444493611653647e-06 + } + }, + { + "timestamp": "2025-08-16T17:41:24.661377", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 36 points saved, 0 lost, 0.0% CPU", + "details": { + "duration": 10.011838674545288, + "points_saved": 36, + "points_rate": 3.5957431167492344, + "variables_saved": 72, + "udp_points_sent": 0, + "points_lost": 0, + "cpu_average": 0.0, + "cpu_max": 0.0, + "delay_average": 0.0, + "delay_max": 0.0, + "read_errors": 0, + "csv_errors": 0, + "udp_errors": 0, + "read_time_avg": 0.04135136471854316, + "csv_write_time_avg": 0.0 + } + }, + { + "timestamp": "2025-08-16T17:41:34.672628", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 36 points saved, 0 lost, 0.2% CPU", + "details": { + "duration": 10.011250972747803, + "points_saved": 36, + "points_rate": 3.5959542017274018, + "variables_saved": 72, + "udp_points_sent": 0, + "points_lost": 0, + "cpu_average": 0.2, + "cpu_max": 0.2, + "delay_average": 0.0, + "delay_max": 0.0, + "read_errors": 0, + "csv_errors": 0, + "udp_errors": 0, + "read_time_avg": 0.04483951462639703, + "csv_write_time_avg": 0.0 + } + }, + { + "timestamp": "2025-08-16T17:41:44.698835", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 37 points saved, 0 lost, 0.3% CPU", + "details": { + "duration": 10.026207447052002, + "points_saved": 37, + "points_rate": 3.6903285908849894, + "variables_saved": 74, + "udp_points_sent": 0, + "points_lost": 0, + "cpu_average": 0.3, + "cpu_max": 0.3, + "delay_average": 0.0, + "delay_max": 0.0, + "read_errors": 0, + "csv_errors": 0, + "udp_errors": 0, + "read_time_avg": 0.045429906329593144, + "csv_write_time_avg": 0.0 + } + }, + { + "timestamp": "2025-08-16T17:41:54.710824", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 36 points saved, 0 lost, 0.2% CPU", + "details": { + "duration": 10.011988639831543, + "points_saved": 36, + "points_rate": 3.5956892576543833, + "variables_saved": 72, + "udp_points_sent": 0, + "points_lost": 0, + "cpu_average": 0.2, + "cpu_max": 0.2, + "delay_average": 0.0, + "delay_max": 0.0, + "read_errors": 0, + "csv_errors": 0, + "udp_errors": 0, + "read_time_avg": 0.04475182294845581, + "csv_write_time_avg": 0.0 + } + }, + { + "timestamp": "2025-08-16T17:42:04.722477", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 36 points saved, 0 lost, 0.0% CPU", + "details": { + "duration": 10.011652946472168, + "points_saved": 36, + "points_rate": 3.5958098220619417, + "variables_saved": 72, + "udp_points_sent": 0, + "points_lost": 0, + "cpu_average": 0.0, + "cpu_max": 0.0, + "delay_average": 0.0, + "delay_max": 0.0, + "read_errors": 0, + "csv_errors": 0, + "udp_errors": 0, + "read_time_avg": 0.04501734839545356, + "csv_write_time_avg": 0.0 + } + }, + { + "timestamp": "2025-08-16T17:42:14.733969", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 36 points saved, 0 lost, 0.0% CPU", + "details": { + "duration": 10.011492252349854, + "points_saved": 36, + "points_rate": 3.5958675382833403, + "variables_saved": 72, + "udp_points_sent": 0, + "points_lost": 0, + "cpu_average": 0.0, + "cpu_max": 0.0, + "delay_average": 0.0, + "delay_max": 0.0, + "read_errors": 0, + "csv_errors": 0, + "udp_errors": 0, + "read_time_avg": 0.03613024950027466, + "csv_write_time_avg": 0.0 + } + }, + { + "timestamp": "2025-08-16T17:42:24.745327", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 36 points saved, 0 lost, 0.0% CPU", + "details": { + "duration": 10.011357545852661, + "points_saved": 36, + "points_rate": 3.5959159220033534, + "variables_saved": 72, + "udp_points_sent": 0, + "points_lost": 0, + "cpu_average": 0.0, + "cpu_max": 0.0, + "delay_average": 0.0, + "delay_max": 0.0, + "read_errors": 0, + "csv_errors": 0, + "udp_errors": 0, + "read_time_avg": 0.039724767208099365, + "csv_write_time_avg": 0.0 + } + }, + { + "timestamp": "2025-08-16T17:42:34.757500", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 36 points saved, 0 lost, 0.0% CPU", + "details": { + "duration": 10.012172937393188, + "points_saved": 36, + "points_rate": 3.5956230705472723, + "variables_saved": 72, + "udp_points_sent": 0, + "points_lost": 0, + "cpu_average": 0.0, + "cpu_max": 0.0, + "delay_average": 0.0, + "delay_max": 0.0, + "read_errors": 0, + "csv_errors": 0, + "udp_errors": 0, + "read_time_avg": 0.04203186432520548, + "csv_write_time_avg": 3.079573313395182e-06 + } + }, + { + "timestamp": "2025-08-16T17:42:44.769105", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 36 points saved, 0 lost, 0.2% CPU", + "details": { + "duration": 10.011605978012085, + "points_saved": 36, + "points_rate": 3.5958266914483783, + "variables_saved": 72, + "udp_points_sent": 0, + "points_lost": 0, + "cpu_average": 0.2, + "cpu_max": 0.2, + "delay_average": 0.0, + "delay_max": 0.0, + "read_errors": 0, + "csv_errors": 0, + "udp_errors": 0, + "read_time_avg": 0.03513310352961222, + "csv_write_time_avg": 0.0 + } + }, + { + "timestamp": "2025-08-16T17:42:54.780854", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 36 points saved, 0 lost, 0.0% CPU", + "details": { + "duration": 10.011748313903809, + "points_saved": 36, + "points_rate": 3.5957755699876137, + "variables_saved": 72, + "udp_points_sent": 0, + "points_lost": 0, + "cpu_average": 0.0, + "cpu_max": 0.0, + "delay_average": 0.0, + "delay_max": 0.0, + "read_errors": 0, + "csv_errors": 0, + "udp_errors": 0, + "read_time_avg": 0.038405398527781166, + "csv_write_time_avg": 0.0 + } + }, + { + "timestamp": "2025-08-16T17:43:04.792520", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 37 points saved, 0 lost, 0.0% CPU", + "details": { + "duration": 10.011666536331177, + "points_saved": 37, + "points_rate": 3.695688411687634, + "variables_saved": 74, + "udp_points_sent": 0, + "points_lost": 0, + "cpu_average": 0.0, + "cpu_max": 0.0, + "delay_average": 0.0, + "delay_max": 0.0, + "read_errors": 0, + "csv_errors": 0, + "udp_errors": 0, + "read_time_avg": 0.04412583402685217, + "csv_write_time_avg": 1.4498427107527448e-06 + } + }, + { + "timestamp": "2025-08-16T17:43:14.804389", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 36 points saved, 1 lost, 0.2% CPU", + "details": { + "duration": 10.011868715286255, + "points_saved": 36, + "points_rate": 3.5957323276757234, + "variables_saved": 72, + "udp_points_sent": 0, + "points_lost": 1, + "cpu_average": 0.2, + "cpu_max": 0.2, + "delay_average": 0.06882286071777344, + "delay_max": 0.06882286071777344, + "read_errors": 0, + "csv_errors": 0, + "udp_errors": 0, + "read_time_avg": 0.056697573926713735, + "csv_write_time_avg": 0.0 + } + }, + { + "timestamp": "2025-08-16T17:43:24.815550", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 36 points saved, 0 lost, 0.0% CPU", + "details": { + "duration": 10.011160373687744, + "points_saved": 36, + "points_rate": 3.595986744415615, + "variables_saved": 72, + "udp_points_sent": 0, + "points_lost": 0, + "cpu_average": 0.0, + "cpu_max": 0.0, + "delay_average": 0.0, + "delay_max": 0.0, + "read_errors": 0, + "csv_errors": 0, + "udp_errors": 0, + "read_time_avg": 0.04259347915649414, + "csv_write_time_avg": 0.0 + } + }, + { + "timestamp": "2025-08-16T17:43:34.828134", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 36 points saved, 0 lost, 0.0% CPU", + "details": { + "duration": 10.012584209442139, + "points_saved": 36, + "points_rate": 3.5954753784793163, + "variables_saved": 72, + "udp_points_sent": 0, + "points_lost": 0, + "cpu_average": 0.0, + "cpu_max": 0.0, + "delay_average": 0.0, + "delay_max": 0.0, + "read_errors": 0, + "csv_errors": 0, + "udp_errors": 0, + "read_time_avg": 0.04154600699742635, + "csv_write_time_avg": 0.0 + } + }, + { + "timestamp": "2025-08-16T17:43:44.840168", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 36 points saved, 0 lost, 0.0% CPU", + "details": { + "duration": 10.012034177780151, + "points_saved": 36, + "points_rate": 3.5956729033042363, + "variables_saved": 72, + "udp_points_sent": 0, + "points_lost": 0, + "cpu_average": 0.0, + "cpu_max": 0.0, + "delay_average": 0.0, + "delay_max": 0.0, + "read_errors": 0, + "csv_errors": 0, + "udp_errors": 0, + "read_time_avg": 0.04695132043626574, + "csv_write_time_avg": 1.7417801751030816e-06 + } + }, + { + "timestamp": "2025-08-16T17:43:54.852602", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 36 points saved, 0 lost, 0.0% CPU", + "details": { + "duration": 10.012434244155884, + "points_saved": 36, + "points_rate": 3.595529231167005, + "variables_saved": 72, + "udp_points_sent": 0, + "points_lost": 0, + "cpu_average": 0.0, + "cpu_max": 0.0, + "delay_average": 0.0, + "delay_max": 0.0, + "read_errors": 0, + "csv_errors": 0, + "udp_errors": 0, + "read_time_avg": 0.046490086449517146, + "csv_write_time_avg": 0.0 + } + }, + { + "timestamp": "2025-08-16T17:44:01.160592", + "level": "info", + "event_type": "application_started", + "message": "Application initialization completed successfully", + "details": {} + }, + { + "timestamp": "2025-08-16T17:44:01.208317", + "level": "info", + "event_type": "dataset_activated", + "message": "Dataset activated: DAR", + "details": { + "dataset_id": "DAR", + "variables_count": 2, + "streaming_count": 2, + "prefix": "gateway_phoenix" + } + }, + { + "timestamp": "2025-08-16T17:44:01.220317", + "level": "info", + "event_type": "dataset_activated", + "message": "Dataset activated: Fast", + "details": { + "dataset_id": "Fast", + "variables_count": 2, + "streaming_count": 2, + "prefix": "fast" + } + }, + { + "timestamp": "2025-08-16T17:44:01.232694", + "level": "info", + "event_type": "csv_recording_started", + "message": "🔥 CRITICAL PRIORITY: CSV recording started with MAXIMUM PRIORITY and performance monitoring: 2 datasets activated", + "details": { + "activated_datasets": 2, + "total_datasets": 3, + "priority": "CRITICAL", + "recording_protection": true, + "performance_monitoring": true + } + }, + { + "timestamp": "2025-08-16T17:44:11.209651", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 36 points saved, 0 lost, 0.0% CPU", + "details": { + "duration": 11.065328121185303, + "points_saved": 36, + "points_rate": 3.253405557045852, + "variables_saved": 72, + "udp_points_sent": 0, + "points_lost": 0, + "cpu_average": 0.0, + "cpu_max": 0.0, + "delay_average": 0.0, + "delay_max": 0.0, + "read_errors": 0, + "csv_errors": 0, + "udp_errors": 0, + "read_time_avg": 0.036451889408959284, + "csv_write_time_avg": 0.00019678804609510634 + } + }, + { + "timestamp": "2025-08-16T17:44:21.222300", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 37 points saved, 0 lost, 0.2% CPU", + "details": { + "duration": 10.012649297714233, + "points_saved": 37, + "points_rate": 3.695325672541697, + "variables_saved": 74, + "udp_points_sent": 0, + "points_lost": 0, + "cpu_average": 0.2, + "cpu_max": 0.2, + "delay_average": 0.0, + "delay_max": 0.0, + "read_errors": 0, + "csv_errors": 0, + "udp_errors": 0, + "read_time_avg": 0.03708207285082018, + "csv_write_time_avg": 0.0 + } + }, + { + "timestamp": "2025-08-16T17:44:31.234808", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 36 points saved, 0 lost, 0.3% CPU", + "details": { + "duration": 10.012507915496826, + "points_saved": 36, + "points_rate": 3.59550277551153, + "variables_saved": 72, + "udp_points_sent": 0, + "points_lost": 0, + "cpu_average": 0.3, + "cpu_max": 0.3, + "delay_average": 0.0, + "delay_max": 0.0, + "read_errors": 0, + "csv_errors": 0, + "udp_errors": 0, + "read_time_avg": 0.033440848191579185, + "csv_write_time_avg": 0.0 + } + }, + { + "timestamp": "2025-08-16T17:44:41.246870", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 36 points saved, 0 lost, 0.0% CPU", + "details": { + "duration": 10.012061357498169, + "points_saved": 36, + "points_rate": 3.595663142139966, + "variables_saved": 72, + "udp_points_sent": 0, + "points_lost": 0, + "cpu_average": 0.0, + "cpu_max": 0.0, + "delay_average": 0.0, + "delay_max": 0.0, + "read_errors": 0, + "csv_errors": 0, + "udp_errors": 0, + "read_time_avg": 0.031726194752587214, + "csv_write_time_avg": 0.0 + } + }, + { + "timestamp": "2025-08-16T17:44:51.258200", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 36 points saved, 0 lost, 0.2% CPU", + "details": { + "duration": 10.011330842971802, + "points_saved": 36, + "points_rate": 3.5959255132670873, + "variables_saved": 72, + "udp_points_sent": 0, + "points_lost": 0, + "cpu_average": 0.2, + "cpu_max": 0.2, + "delay_average": 0.0, + "delay_max": 0.0, + "read_errors": 0, + "csv_errors": 0, + "udp_errors": 0, + "read_time_avg": 0.03945233424504598, + "csv_write_time_avg": 1.3973977830674912e-06 + } + }, + { + "timestamp": "2025-08-16T17:45:01.269713", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 36 points saved, 0 lost, 0.2% CPU", + "details": { + "duration": 10.011512756347656, + "points_saved": 36, + "points_rate": 3.595860173795885, + "variables_saved": 72, + "udp_points_sent": 0, + "points_lost": 0, + "cpu_average": 0.2, + "cpu_max": 0.2, + "delay_average": 0.0, + "delay_max": 0.0, + "read_errors": 0, + "csv_errors": 0, + "udp_errors": 0, + "read_time_avg": 0.03561492098702325, + "csv_write_time_avg": 0.0 + } + }, + { + "timestamp": "2025-08-16T17:45:11.281919", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 36 points saved, 0 lost, 0.2% CPU", + "details": { + "duration": 10.012205839157104, + "points_saved": 36, + "points_rate": 3.5956112547353225, + "variables_saved": 72, + "udp_points_sent": 0, + "points_lost": 0, + "cpu_average": 0.2, + "cpu_max": 0.2, + "delay_average": 0.0, + "delay_max": 0.0, + "read_errors": 0, + "csv_errors": 0, + "udp_errors": 0, + "read_time_avg": 0.034524612956576876, + "csv_write_time_avg": 0.0 + } + }, + { + "timestamp": "2025-08-16T17:45:21.294101", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 36 points saved, 0 lost, 0.0% CPU", + "details": { + "duration": 10.012181758880615, + "points_saved": 36, + "points_rate": 3.595619902532101, + "variables_saved": 72, + "udp_points_sent": 0, + "points_lost": 0, + "cpu_average": 0.0, + "cpu_max": 0.0, + "delay_average": 0.0, + "delay_max": 0.0, + "read_errors": 0, + "csv_errors": 0, + "udp_errors": 0, + "read_time_avg": 0.03704675038655599, + "csv_write_time_avg": 0.0 + } + }, + { + "timestamp": "2025-08-16T17:45:31.305187", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 36 points saved, 0 lost, 0.0% CPU", + "details": { + "duration": 10.011086463928223, + "points_saved": 36, + "points_rate": 3.596013292834358, + "variables_saved": 72, + "udp_points_sent": 0, + "points_lost": 0, + "cpu_average": 0.0, + "cpu_max": 0.0, + "delay_average": 0.0, + "delay_max": 0.0, + "read_errors": 0, + "csv_errors": 0, + "udp_errors": 0, + "read_time_avg": 0.0359831518597073, + "csv_write_time_avg": 0.0 + } + }, + { + "timestamp": "2025-08-16T17:45:41.316898", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 37 points saved, 0 lost, 0.2% CPU", + "details": { + "duration": 10.011711120605469, + "points_saved": 37, + "points_rate": 3.6956719540028424, + "variables_saved": 74, + "udp_points_sent": 0, + "points_lost": 0, + "cpu_average": 0.2, + "cpu_max": 0.2, + "delay_average": 0.0, + "delay_max": 0.0, + "read_errors": 0, + "csv_errors": 0, + "udp_errors": 0, + "read_time_avg": 0.037827994372393633, + "csv_write_time_avg": 2.6999293146906673e-06 + } + }, + { + "timestamp": "2025-08-16T17:45:51.336767", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 36 points saved, 0 lost, 0.0% CPU", + "details": { + "duration": 10.01986813545227, + "points_saved": 36, + "points_rate": 3.592861653800103, + "variables_saved": 72, + "udp_points_sent": 0, + "points_lost": 0, + "cpu_average": 0.0, + "cpu_max": 0.0, + "delay_average": 0.0, + "delay_max": 0.0, + "read_errors": 0, + "csv_errors": 0, + "udp_errors": 0, + "read_time_avg": 0.048847191863589816, + "csv_write_time_avg": 0.0 + } + }, + { + "timestamp": "2025-08-16T17:46:01.349178", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 36 points saved, 0 lost, 0.0% CPU", + "details": { + "duration": 10.012411832809448, + "points_saved": 36, + "points_rate": 3.59553727924299, + "variables_saved": 72, + "udp_points_sent": 0, + "points_lost": 0, + "cpu_average": 0.0, + "cpu_max": 0.0, + "delay_average": 0.0, + "delay_max": 0.0, + "read_errors": 0, + "csv_errors": 0, + "udp_errors": 0, + "read_time_avg": 0.05066521300209893, + "csv_write_time_avg": 0.0 + } + }, + { + "timestamp": "2025-08-16T17:46:11.360928", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 36 points saved, 0 lost, 0.2% CPU", + "details": { + "duration": 10.011749267578125, + "points_saved": 36, + "points_rate": 3.595775227470166, + "variables_saved": 72, + "udp_points_sent": 0, + "points_lost": 0, + "cpu_average": 0.2, + "cpu_max": 0.2, + "delay_average": 0.0, + "delay_max": 0.0, + "read_errors": 0, + "csv_errors": 0, + "udp_errors": 0, + "read_time_avg": 0.04360498322380914, + "csv_write_time_avg": 0.0 + } + }, + { + "timestamp": "2025-08-16T17:46:21.373005", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 36 points saved, 0 lost, 0.2% CPU", + "details": { + "duration": 10.012077808380127, + "points_saved": 36, + "points_rate": 3.5956572340926014, + "variables_saved": 72, + "udp_points_sent": 0, + "points_lost": 0, + "cpu_average": 0.2, + "cpu_max": 0.2, + "delay_average": 0.0, + "delay_max": 0.0, + "read_errors": 0, + "csv_errors": 0, + "udp_errors": 0, + "read_time_avg": 0.0415983862347073, + "csv_write_time_avg": 2.0662943522135415e-06 + } + }, + { + "timestamp": "2025-08-16T17:46:31.385128", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 36 points saved, 0 lost, 0.0% CPU", + "details": { + "duration": 10.01212215423584, + "points_saved": 36, + "points_rate": 3.5956413081485867, + "variables_saved": 72, + "udp_points_sent": 0, + "points_lost": 0, + "cpu_average": 0.0, + "cpu_max": 0.0, + "delay_average": 0.0, + "delay_max": 0.0, + "read_errors": 0, + "csv_errors": 0, + "udp_errors": 0, + "read_time_avg": 0.042348391479916044, + "csv_write_time_avg": 0.0 + } + }, + { + "timestamp": "2025-08-16T17:46:41.397509", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 36 points saved, 0 lost, 0.0% CPU", + "details": { + "duration": 10.012381792068481, + "points_saved": 36, + "points_rate": 3.5955480671460367, + "variables_saved": 72, + "udp_points_sent": 0, + "points_lost": 0, + "cpu_average": 0.0, + "cpu_max": 0.0, + "delay_average": 0.0, + "delay_max": 0.0, + "read_errors": 0, + "csv_errors": 0, + "udp_errors": 0, + "read_time_avg": 0.03914252916971842, + "csv_write_time_avg": 0.0 + } + }, + { + "timestamp": "2025-08-16T17:46:51.410348", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 36 points saved, 0 lost, 0.0% CPU", + "details": { + "duration": 10.012839078903198, + "points_saved": 36, + "points_rate": 3.5953838582956057, + "variables_saved": 72, + "udp_points_sent": 0, + "points_lost": 0, + "cpu_average": 0.0, + "cpu_max": 0.0, + "delay_average": 0.0, + "delay_max": 0.0, + "read_errors": 0, + "csv_errors": 0, + "udp_errors": 0, + "read_time_avg": 0.04319175746705797, + "csv_write_time_avg": 0.0 + } + }, + { + "timestamp": "2025-08-16T17:47:01.422448", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 37 points saved, 0 lost, 0.3% CPU", + "details": { + "duration": 10.012099742889404, + "points_saved": 37, + "points_rate": 3.695528505524269, + "variables_saved": 74, + "udp_points_sent": 0, + "points_lost": 0, + "cpu_average": 0.3, + "cpu_max": 0.3, + "delay_average": 0.0, + "delay_max": 0.0, + "read_errors": 0, + "csv_errors": 0, + "udp_errors": 0, + "read_time_avg": 0.04194447800919816, + "csv_write_time_avg": 0.0 + } + }, + { + "timestamp": "2025-08-16T17:47:11.435141", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 36 points saved, 0 lost, 0.2% CPU", + "details": { + "duration": 10.01269245147705, + "points_saved": 36, + "points_rate": 3.595436509656237, + "variables_saved": 72, + "udp_points_sent": 0, + "points_lost": 0, + "cpu_average": 0.2, + "cpu_max": 0.2, + "delay_average": 0.0, + "delay_max": 0.0, + "read_errors": 0, + "csv_errors": 0, + "udp_errors": 0, + "read_time_avg": 0.03776511881086561, + "csv_write_time_avg": 0.0 + } + }, + { + "timestamp": "2025-08-16T17:47:21.448595", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 36 points saved, 0 lost, 0.2% CPU", + "details": { + "duration": 10.013454675674438, + "points_saved": 36, + "points_rate": 3.5951628250192567, + "variables_saved": 72, + "udp_points_sent": 0, + "points_lost": 0, + "cpu_average": 0.2, + "cpu_max": 0.2, + "delay_average": 0.0, + "delay_max": 0.0, + "read_errors": 0, + "csv_errors": 0, + "udp_errors": 0, + "read_time_avg": 0.03620455662409464, + "csv_write_time_avg": 0.0 + } + }, + { + "timestamp": "2025-08-16T17:47:31.463186", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 36 points saved, 0 lost, 0.0% CPU", + "details": { + "duration": 10.014590501785278, + "points_saved": 36, + "points_rate": 3.5947550719704777, + "variables_saved": 72, + "udp_points_sent": 0, + "points_lost": 0, + "cpu_average": 0.0, + "cpu_max": 0.0, + "delay_average": 0.0, + "delay_max": 0.0, + "read_errors": 0, + "csv_errors": 0, + "udp_errors": 0, + "read_time_avg": 0.039609584543440074, + "csv_write_time_avg": 1.4967388576931423e-06 + } + }, + { + "timestamp": "2025-08-16T17:47:41.474959", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 36 points saved, 0 lost, 0.0% CPU", + "details": { + "duration": 10.011773347854614, + "points_saved": 36, + "points_rate": 3.5957665789262303, + "variables_saved": 72, + "udp_points_sent": 0, + "points_lost": 0, + "cpu_average": 0.0, + "cpu_max": 0.0, + "delay_average": 0.0, + "delay_max": 0.0, + "read_errors": 0, + "csv_errors": 0, + "udp_errors": 0, + "read_time_avg": 0.03736231724421183, + "csv_write_time_avg": 0.0 + } + }, + { + "timestamp": "2025-08-16T17:47:51.486457", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 36 points saved, 0 lost, 0.0% CPU", + "details": { + "duration": 10.011498212814331, + "points_saved": 36, + "points_rate": 3.5958653974408534, + "variables_saved": 72, + "udp_points_sent": 0, + "points_lost": 0, + "cpu_average": 0.0, + "cpu_max": 0.0, + "delay_average": 0.0, + "delay_max": 0.0, + "read_errors": 0, + "csv_errors": 0, + "udp_errors": 0, + "read_time_avg": 0.048889378706614174, + "csv_write_time_avg": 0.0 + } + }, + { + "timestamp": "2025-08-16T17:48:01.500380", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 36 points saved, 0 lost, 0.0% CPU", + "details": { + "duration": 10.013922452926636, + "points_saved": 36, + "points_rate": 3.5949948852938003, + "variables_saved": 72, + "udp_points_sent": 0, + "points_lost": 0, + "cpu_average": 0.0, + "cpu_max": 0.0, + "delay_average": 0.0, + "delay_max": 0.0, + "read_errors": 0, + "csv_errors": 0, + "udp_errors": 0, + "read_time_avg": 0.037998729281955294, + "csv_write_time_avg": 3.808074527316623e-06 + } + }, + { + "timestamp": "2025-08-16T17:48:11.513572", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 36 points saved, 0 lost, 0.0% CPU", + "details": { + "duration": 10.013192415237427, + "points_saved": 36, + "points_rate": 3.595256987693309, + "variables_saved": 72, + "udp_points_sent": 0, + "points_lost": 0, + "cpu_average": 0.0, + "cpu_max": 0.0, + "delay_average": 0.0, + "delay_max": 0.0, + "read_errors": 0, + "csv_errors": 0, + "udp_errors": 0, + "read_time_avg": 0.03640822569529215, + "csv_write_time_avg": 0.0 + } + }, + { + "timestamp": "2025-08-16T17:48:21.526104", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 36 points saved, 0 lost, 0.0% CPU", + "details": { + "duration": 10.012531995773315, + "points_saved": 36, + "points_rate": 3.5954941282781436, + "variables_saved": 72, + "udp_points_sent": 0, + "points_lost": 0, + "cpu_average": 0.0, + "cpu_max": 0.0, + "delay_average": 0.0, + "delay_max": 0.0, + "read_errors": 0, + "csv_errors": 0, + "udp_errors": 0, + "read_time_avg": 0.039086997509002686, + "csv_write_time_avg": 0.0 + } + }, + { + "timestamp": "2025-08-16T17:48:31.538450", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 37 points saved, 0 lost, 0.0% CPU", + "details": { + "duration": 10.012345552444458, + "points_saved": 37, + "points_rate": 3.6954377779107572, + "variables_saved": 74, + "udp_points_sent": 0, + "points_lost": 0, + "cpu_average": 0.0, + "cpu_max": 0.0, + "delay_average": 0.0, + "delay_max": 0.0, + "read_errors": 0, + "csv_errors": 0, + "udp_errors": 0, + "read_time_avg": 0.03997675792590992, + "csv_write_time_avg": 0.0 + } + }, + { + "timestamp": "2025-08-16T17:48:41.551341", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 36 points saved, 0 lost, 0.0% CPU", + "details": { + "duration": 10.0128915309906, + "points_saved": 36, + "points_rate": 3.5953650240370107, + "variables_saved": 72, + "udp_points_sent": 0, + "points_lost": 0, + "cpu_average": 0.0, + "cpu_max": 0.0, + "delay_average": 0.0, + "delay_max": 0.0, + "read_errors": 0, + "csv_errors": 0, + "udp_errors": 0, + "read_time_avg": 0.03940553135342068, + "csv_write_time_avg": 4.238552517361111e-06 + } + }, + { + "timestamp": "2025-08-16T17:48:51.564265", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 36 points saved, 0 lost, 0.0% CPU", + "details": { + "duration": 10.012923955917358, + "points_saved": 36, + "points_rate": 3.595353381139483, + "variables_saved": 72, + "udp_points_sent": 0, + "points_lost": 0, + "cpu_average": 0.0, + "cpu_max": 0.0, + "delay_average": 0.0, + "delay_max": 0.0, + "read_errors": 0, + "csv_errors": 0, + "udp_errors": 0, + "read_time_avg": 0.03923845291137695, + "csv_write_time_avg": 0.0 + } + }, + { + "timestamp": "2025-08-16T17:49:01.579024", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 36 points saved, 0 lost, 0.0% CPU", + "details": { + "duration": 10.014758586883545, + "points_saved": 36, + "points_rate": 3.5946947385381463, + "variables_saved": 72, + "udp_points_sent": 0, + "points_lost": 0, + "cpu_average": 0.0, + "cpu_max": 0.0, + "delay_average": 0.0, + "delay_max": 0.0, + "read_errors": 0, + "csv_errors": 0, + "udp_errors": 0, + "read_time_avg": 0.03705465131335788, + "csv_write_time_avg": 2.165635426839193e-06 + } + }, + { + "timestamp": "2025-08-16T17:49:11.592784", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 36 points saved, 0 lost, 0.0% CPU", + "details": { + "duration": 10.013760089874268, + "points_saved": 36, + "points_rate": 3.5950531745215812, + "variables_saved": 72, + "udp_points_sent": 0, + "points_lost": 0, + "cpu_average": 0.0, + "cpu_max": 0.0, + "delay_average": 0.0, + "delay_max": 0.0, + "read_errors": 0, + "csv_errors": 0, + "udp_errors": 0, + "read_time_avg": 0.034785840246412486, + "csv_write_time_avg": 0.0 + } + }, + { + "timestamp": "2025-08-16T17:49:21.605609", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 36 points saved, 0 lost, 0.0% CPU", + "details": { + "duration": 10.012825012207031, + "points_saved": 36, + "points_rate": 3.5953889093348756, + "variables_saved": 72, + "udp_points_sent": 0, + "points_lost": 0, + "cpu_average": 0.0, + "cpu_max": 0.0, + "delay_average": 0.0, + "delay_max": 0.0, + "read_errors": 0, + "csv_errors": 0, + "udp_errors": 0, + "read_time_avg": 0.04109643565283881, + "csv_write_time_avg": 0.0 + } + }, + { + "timestamp": "2025-08-16T17:49:31.618150", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 36 points saved, 0 lost, 0.0% CPU", + "details": { + "duration": 10.012541055679321, + "points_saved": 36, + "points_rate": 3.595490874874371, + "variables_saved": 72, + "udp_points_sent": 0, + "points_lost": 0, + "cpu_average": 0.0, + "cpu_max": 0.0, + "delay_average": 0.0, + "delay_max": 0.0, + "read_errors": 0, + "csv_errors": 0, + "udp_errors": 0, + "read_time_avg": 0.03830966022279528, + "csv_write_time_avg": 0.0 + } + }, + { + "timestamp": "2025-08-16T17:49:41.630125", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 36 points saved, 0 lost, 0.0% CPU", + "details": { + "duration": 10.011974811553955, + "points_saved": 36, + "points_rate": 3.5956942239262837, + "variables_saved": 72, + "udp_points_sent": 0, + "points_lost": 0, + "cpu_average": 0.0, + "cpu_max": 0.0, + "delay_average": 0.0, + "delay_max": 0.0, + "read_errors": 0, + "csv_errors": 0, + "udp_errors": 0, + "read_time_avg": 0.03487048546473185, + "csv_write_time_avg": 0.0 + } + }, + { + "timestamp": "2025-08-16T17:50:46.107207", + "level": "info", + "event_type": "application_started", + "message": "Application initialization completed successfully", + "details": {} + }, + { + "timestamp": "2025-08-16T17:50:46.155548", + "level": "info", + "event_type": "dataset_activated", + "message": "Dataset activated: DAR", + "details": { + "dataset_id": "DAR", + "variables_count": 2, + "streaming_count": 2, + "prefix": "gateway_phoenix" + } + }, + { + "timestamp": "2025-08-16T17:50:46.168431", + "level": "info", + "event_type": "dataset_activated", + "message": "Dataset activated: Fast", + "details": { + "dataset_id": "Fast", + "variables_count": 2, + "streaming_count": 2, + "prefix": "fast" + } + }, + { + "timestamp": "2025-08-16T17:50:46.182343", + "level": "info", + "event_type": "csv_recording_started", + "message": "🔥 CRITICAL PRIORITY: CSV recording started with MAXIMUM PRIORITY and performance monitoring: 2 datasets activated", + "details": { + "activated_datasets": 2, + "total_datasets": 3, + "priority": "CRITICAL", + "recording_protection": true, + "performance_monitoring": true + } + }, + { + "timestamp": "2025-08-16T17:50:56.157022", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 37 points saved, 0 lost, 0.0% CPU", + "details": { + "duration": 11.070454359054565, + "points_saved": 37, + "points_rate": 3.34222957793395, + "variables_saved": 74, + "udp_points_sent": 0, + "points_lost": 0, + "cpu_average": 0.0, + "cpu_max": 0.0, + "delay_average": 0.0, + "delay_max": 0.0, + "read_errors": 0, + "csv_errors": 0, + "udp_errors": 0, + "read_time_avg": 0.04276608776401829, + "csv_write_time_avg": 0.000244295274889147 + } + }, + { + "timestamp": "2025-08-16T17:51:06.170160", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 36 points saved, 0 lost, 0.0% CPU", + "details": { + "duration": 10.013138055801392, + "points_saved": 36, + "points_rate": 3.5952765056647147, + "variables_saved": 72, + "udp_points_sent": 0, + "points_lost": 0, + "cpu_average": 0.0, + "cpu_max": 0.0, + "delay_average": 0.0, + "delay_max": 0.0, + "read_errors": 0, + "csv_errors": 0, + "udp_errors": 0, + "read_time_avg": 0.046510808997684054, + "csv_write_time_avg": 2.7841991848415797e-05 + } + }, + { + "timestamp": "2025-08-16T17:51:16.182989", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 36 points saved, 0 lost, 3.1% CPU", + "details": { + "duration": 10.012829065322876, + "points_saved": 36, + "points_rate": 3.5953874539492237, + "variables_saved": 72, + "udp_points_sent": 0, + "points_lost": 0, + "cpu_average": 3.1, + "cpu_max": 3.1, + "delay_average": 0.0, + "delay_max": 0.0, + "read_errors": 0, + "csv_errors": 0, + "udp_errors": 0, + "read_time_avg": 0.03804396258460151, + "csv_write_time_avg": 3.0610296461317274e-05 + } + }, + { + "timestamp": "2025-08-16T17:51:26.202381", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 36 points saved, 0 lost, 0.6% CPU", + "details": { + "duration": 10.019392728805542, + "points_saved": 36, + "points_rate": 3.5930321302308834, + "variables_saved": 72, + "udp_points_sent": 0, + "points_lost": 0, + "cpu_average": 0.6, + "cpu_max": 0.6, + "delay_average": 0.0, + "delay_max": 0.0, + "read_errors": 0, + "csv_errors": 0, + "udp_errors": 0, + "read_time_avg": 0.03497481346130371, + "csv_write_time_avg": 7.715490129258898e-06 + } + }, + { + "timestamp": "2025-08-16T17:51:36.214771", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 36 points saved, 0 lost, 0.3% CPU", + "details": { + "duration": 10.012389421463013, + "points_saved": 36, + "points_rate": 3.595545327355003, + "variables_saved": 72, + "udp_points_sent": 0, + "points_lost": 0, + "cpu_average": 0.3, + "cpu_max": 0.3, + "delay_average": 0.0, + "delay_max": 0.0, + "read_errors": 0, + "csv_errors": 0, + "udp_errors": 0, + "read_time_avg": 0.039346019426981606, + "csv_write_time_avg": 0.0 + } + }, + { + "timestamp": "2025-08-16T17:51:46.227696", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 36 points saved, 0 lost, 0.2% CPU", + "details": { + "duration": 10.012925148010254, + "points_saved": 36, + "points_rate": 3.5953529530932165, + "variables_saved": 72, + "udp_points_sent": 0, + "points_lost": 0, + "cpu_average": 0.2, + "cpu_max": 0.2, + "delay_average": 0.0, + "delay_max": 0.0, + "read_errors": 0, + "csv_errors": 0, + "udp_errors": 0, + "read_time_avg": 0.03932499885559082, + "csv_write_time_avg": 0.0 + } + }, + { + "timestamp": "2025-08-16T17:51:56.240555", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 36 points saved, 0 lost, 0.2% CPU", + "details": { + "duration": 10.012859106063843, + "points_saved": 36, + "points_rate": 3.5953766670099454, + "variables_saved": 72, + "udp_points_sent": 0, + "points_lost": 0, + "cpu_average": 0.2, + "cpu_max": 0.2, + "delay_average": 0.0, + "delay_max": 0.0, + "read_errors": 0, + "csv_errors": 0, + "udp_errors": 0, + "read_time_avg": 0.04122459226184421, + "csv_write_time_avg": 2.602736155192057e-06 + } + }, + { + "timestamp": "2025-08-16T17:52:06.253745", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 36 points saved, 0 lost, 0.0% CPU", + "details": { + "duration": 10.013189792633057, + "points_saved": 36, + "points_rate": 3.595257929344959, + "variables_saved": 72, + "udp_points_sent": 0, + "points_lost": 0, + "cpu_average": 0.0, + "cpu_max": 0.0, + "delay_average": 0.0, + "delay_max": 0.0, + "read_errors": 0, + "csv_errors": 0, + "udp_errors": 0, + "read_time_avg": 0.04294577572080824, + "csv_write_time_avg": 1.4636251661512588e-06 + } + }, + { + "timestamp": "2025-08-16T17:52:16.266571", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 36 points saved, 0 lost, 0.3% CPU", + "details": { + "duration": 10.012826204299927, + "points_saved": 36, + "points_rate": 3.5953884812801498, + "variables_saved": 72, + "udp_points_sent": 0, + "points_lost": 0, + "cpu_average": 0.3, + "cpu_max": 0.3, + "delay_average": 0.0, + "delay_max": 0.0, + "read_errors": 0, + "csv_errors": 0, + "udp_errors": 0, + "read_time_avg": 0.0387861794895596, + "csv_write_time_avg": 0.0 + } + }, + { + "timestamp": "2025-08-16T17:52:26.279174", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 37 points saved, 0 lost, 0.2% CPU", + "details": { + "duration": 10.012603044509888, + "points_saved": 37, + "points_rate": 3.695342743092951, + "variables_saved": 74, + "udp_points_sent": 0, + "points_lost": 0, + "cpu_average": 0.2, + "cpu_max": 0.2, + "delay_average": 0.0, + "delay_max": 0.0, + "read_errors": 0, + "csv_errors": 0, + "udp_errors": 0, + "read_time_avg": 0.03841180414766879, + "csv_write_time_avg": 0.0 + } + }, + { + "timestamp": "2025-08-16T17:52:36.292670", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 36 points saved, 0 lost, 0.0% CPU", + "details": { + "duration": 10.013496160507202, + "points_saved": 36, + "points_rate": 3.595147930648084, + "variables_saved": 72, + "udp_points_sent": 0, + "points_lost": 0, + "cpu_average": 0.0, + "cpu_max": 0.0, + "delay_average": 0.0, + "delay_max": 0.0, + "read_errors": 0, + "csv_errors": 0, + "udp_errors": 0, + "read_time_avg": 0.03261729743745592, + "csv_write_time_avg": 5.74191411336263e-06 + } + }, + { + "timestamp": "2025-08-16T17:52:46.305377", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 36 points saved, 0 lost, 0.2% CPU", + "details": { + "duration": 10.012706756591797, + "points_saved": 36, + "points_rate": 3.5954313728702427, + "variables_saved": 72, + "udp_points_sent": 0, + "points_lost": 0, + "cpu_average": 0.2, + "cpu_max": 0.2, + "delay_average": 0.0, + "delay_max": 0.0, + "read_errors": 0, + "csv_errors": 0, + "udp_errors": 0, + "read_time_avg": 0.03950485255983141, + "csv_write_time_avg": 0.0 + } + }, + { + "timestamp": "2025-08-16T17:52:56.319032", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 36 points saved, 0 lost, 0.0% CPU", + "details": { + "duration": 10.013654947280884, + "points_saved": 36, + "points_rate": 3.5950909222986027, + "variables_saved": 72, + "udp_points_sent": 0, + "points_lost": 0, + "cpu_average": 0.0, + "cpu_max": 0.0, + "delay_average": 0.0, + "delay_max": 0.0, + "read_errors": 0, + "csv_errors": 0, + "udp_errors": 0, + "read_time_avg": 0.037491301695505776, + "csv_write_time_avg": 0.0 + } + }, + { + "timestamp": "2025-08-16T17:53:06.332901", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 36 points saved, 0 lost, 0.0% CPU", + "details": { + "duration": 10.013869047164917, + "points_saved": 36, + "points_rate": 3.5950140580470404, + "variables_saved": 72, + "udp_points_sent": 0, + "points_lost": 0, + "cpu_average": 0.0, + "cpu_max": 0.0, + "delay_average": 0.0, + "delay_max": 0.0, + "read_errors": 0, + "csv_errors": 0, + "udp_errors": 0, + "read_time_avg": 0.03695770104726156, + "csv_write_time_avg": 0.0 + } + }, + { + "timestamp": "2025-08-16T17:53:16.352174", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 36 points saved, 0 lost, 0.3% CPU", + "details": { + "duration": 10.019272804260254, + "points_saved": 36, + "points_rate": 3.593075136619954, + "variables_saved": 72, + "udp_points_sent": 0, + "points_lost": 0, + "cpu_average": 0.3, + "cpu_max": 0.3, + "delay_average": 0.0, + "delay_max": 0.0, + "read_errors": 0, + "csv_errors": 0, + "udp_errors": 0, + "read_time_avg": 0.035578529040018715, + "csv_write_time_avg": 0.0 + } + }, + { + "timestamp": "2025-08-16T17:53:26.365408", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 36 points saved, 0 lost, 0.3% CPU", + "details": { + "duration": 10.01323390007019, + "points_saved": 36, + "points_rate": 3.5952420925419157, + "variables_saved": 72, + "udp_points_sent": 0, + "points_lost": 0, + "cpu_average": 0.3, + "cpu_max": 0.3, + "delay_average": 0.0, + "delay_max": 0.0, + "read_errors": 0, + "csv_errors": 0, + "udp_errors": 0, + "read_time_avg": 0.03323685460620456, + "csv_write_time_avg": 0.0 + } + }, + { + "timestamp": "2025-08-16T17:53:36.378311", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 36 points saved, 0 lost, 0.0% CPU", + "details": { + "duration": 10.012903451919556, + "points_saved": 36, + "points_rate": 3.595360743551213, + "variables_saved": 72, + "udp_points_sent": 0, + "points_lost": 0, + "cpu_average": 0.0, + "cpu_max": 0.0, + "delay_average": 0.0, + "delay_max": 0.0, + "read_errors": 0, + "csv_errors": 0, + "udp_errors": 0, + "read_time_avg": 0.03913132349650065, + "csv_write_time_avg": 0.0 + } + }, + { + "timestamp": "2025-08-16T17:53:46.391772", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 37 points saved, 0 lost, 0.0% CPU", + "details": { + "duration": 10.013461112976074, + "points_saved": 37, + "points_rate": 3.695026083643853, + "variables_saved": 74, + "udp_points_sent": 0, + "points_lost": 0, + "cpu_average": 0.0, + "cpu_max": 0.0, + "delay_average": 0.0, + "delay_max": 0.0, + "read_errors": 0, + "csv_errors": 0, + "udp_errors": 0, + "read_time_avg": 0.03530258745760531, + "csv_write_time_avg": 1.5658301276129645e-06 + } + }, + { + "timestamp": "2025-08-16T17:53:56.405491", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 36 points saved, 0 lost, 0.0% CPU", + "details": { + "duration": 10.013718128204346, + "points_saved": 36, + "points_rate": 3.5950682392989926, + "variables_saved": 72, + "udp_points_sent": 0, + "points_lost": 0, + "cpu_average": 0.0, + "cpu_max": 0.0, + "delay_average": 0.0, + "delay_max": 0.0, + "read_errors": 0, + "csv_errors": 0, + "udp_errors": 0, + "read_time_avg": 0.037487030029296875, + "csv_write_time_avg": 0.0 + } + }, + { + "timestamp": "2025-08-16T17:54:06.418616", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 36 points saved, 0 lost, 0.2% CPU", + "details": { + "duration": 10.013125658035278, + "points_saved": 36, + "points_rate": 3.5952809571615547, + "variables_saved": 72, + "udp_points_sent": 0, + "points_lost": 0, + "cpu_average": 0.2, + "cpu_max": 0.2, + "delay_average": 0.0, + "delay_max": 0.0, + "read_errors": 0, + "csv_errors": 0, + "udp_errors": 0, + "read_time_avg": 0.03964172469245063, + "csv_write_time_avg": 0.0 + } + }, + { + "timestamp": "2025-08-16T17:54:16.431687", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 36 points saved, 0 lost, 0.0% CPU", + "details": { + "duration": 10.013070821762085, + "points_saved": 36, + "points_rate": 3.5953006466067094, + "variables_saved": 72, + "udp_points_sent": 0, + "points_lost": 0, + "cpu_average": 0.0, + "cpu_max": 0.0, + "delay_average": 0.0, + "delay_max": 0.0, + "read_errors": 0, + "csv_errors": 0, + "udp_errors": 0, + "read_time_avg": 0.03765919473436144, + "csv_write_time_avg": 4.516707526312934e-06 + } + }, + { + "timestamp": "2025-08-16T17:54:26.444920", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 36 points saved, 0 lost, 0.0% CPU", + "details": { + "duration": 10.013233184814453, + "points_saved": 36, + "points_rate": 3.5952423493538253, + "variables_saved": 72, + "udp_points_sent": 0, + "points_lost": 0, + "cpu_average": 0.0, + "cpu_max": 0.0, + "delay_average": 0.0, + "delay_max": 0.0, + "read_errors": 0, + "csv_errors": 0, + "udp_errors": 0, + "read_time_avg": 0.037419060866038, + "csv_write_time_avg": 2.3245811462402344e-06 + } + }, + { + "timestamp": "2025-08-16T17:54:36.460973", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 36 points saved, 0 lost, 0.5% CPU", + "details": { + "duration": 10.016053199768066, + "points_saved": 36, + "points_rate": 3.5942301106022105, + "variables_saved": 72, + "udp_points_sent": 0, + "points_lost": 0, + "cpu_average": 0.5, + "cpu_max": 0.5, + "delay_average": 0.0, + "delay_max": 0.0, + "read_errors": 0, + "csv_errors": 0, + "udp_errors": 0, + "read_time_avg": 0.03436344199710422, + "csv_write_time_avg": 0.0 + } + }, + { + "timestamp": "2025-08-16T17:54:46.474547", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 36 points saved, 0 lost, 0.3% CPU", + "details": { + "duration": 10.013573408126831, + "points_saved": 36, + "points_rate": 3.595120196630612, + "variables_saved": 72, + "udp_points_sent": 0, + "points_lost": 0, + "cpu_average": 0.3, + "cpu_max": 0.3, + "delay_average": 0.0, + "delay_max": 0.0, + "read_errors": 0, + "csv_errors": 0, + "udp_errors": 0, + "read_time_avg": 0.03271661864386664, + "csv_write_time_avg": 0.0 + } + }, + { + "timestamp": "2025-08-16T17:54:56.488189", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 36 points saved, 0 lost, 0.0% CPU", + "details": { + "duration": 10.01364254951477, + "points_saved": 36, + "points_rate": 3.5950953733358944, + "variables_saved": 72, + "udp_points_sent": 0, + "points_lost": 0, + "cpu_average": 0.0, + "cpu_max": 0.0, + "delay_average": 0.0, + "delay_max": 0.0, + "read_errors": 0, + "csv_errors": 0, + "udp_errors": 0, + "read_time_avg": 0.0374917189280192, + "csv_write_time_avg": 0.0 + } + }, + { + "timestamp": "2025-08-16T17:55:06.502096", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 37 points saved, 0 lost, 0.0% CPU", + "details": { + "duration": 10.013907194137573, + "points_saved": 37, + "points_rate": 3.694861484402497, + "variables_saved": 74, + "udp_points_sent": 0, + "points_lost": 0, + "cpu_average": 0.0, + "cpu_max": 0.0, + "delay_average": 0.0, + "delay_max": 0.0, + "read_errors": 0, + "csv_errors": 0, + "udp_errors": 0, + "read_time_avg": 0.03852872590760927, + "csv_write_time_avg": 0.0 + } + }, + { + "timestamp": "2025-08-16T17:55:08.307569", + "level": "info", + "event_type": "plot_session_created", + "message": "Plot session 'UR29' created and started", + "details": { + "session_id": "plot_1_1755359708307_2", + "variables": [ + "UR29_Brix", + "UR29_ma", + "AUX Blink_1.0S", + "AUX Blink_1.6S" + ], + "time_window": 36, + "trigger_variable": null, + "auto_started": true + } + }, + { + "timestamp": "2025-08-16T17:55:16.515549", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 35 points saved, 0 lost, 0.3% CPU", + "details": { + "duration": 10.013452291488647, + "points_saved": 35, + "points_rate": 3.4952980232152018, + "variables_saved": 70, + "udp_points_sent": 0, + "points_lost": 0, + "cpu_average": 0.3, + "cpu_max": 0.3, + "delay_average": 0.0, + "delay_max": 0.0, + "read_errors": 0, + "csv_errors": 0, + "udp_errors": 0, + "read_time_avg": 0.06907689911978586, + "csv_write_time_avg": 6.014960152762277e-06 + } + }, + { + "timestamp": "2025-08-16T17:55:26.548136", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 37 points saved, 0 lost, 0.3% CPU", + "details": { + "duration": 10.032587766647339, + "points_saved": 37, + "points_rate": 3.6879816913243464, + "variables_saved": 74, + "udp_points_sent": 0, + "points_lost": 0, + "cpu_average": 0.3, + "cpu_max": 0.3, + "delay_average": 0.0, + "delay_max": 0.0, + "read_errors": 0, + "csv_errors": 0, + "udp_errors": 0, + "read_time_avg": 0.06016896222088788, + "csv_write_time_avg": 3.0472471907332136e-05 + } + }, + { + "timestamp": "2025-08-16T17:55:31.264778", + "level": "info", + "event_type": "udp_streaming_stopped", + "message": "UDP streaming to PlotJuggler stopped (CSV recording continues)", + "details": {} + }, + { + "timestamp": "2025-08-16T17:55:33.278864", + "level": "info", + "event_type": "csv_recording_stopped", + "message": "🔥 CRITICAL: CSV recording stopped (dataset threads continue for UDP streaming)", + "details": { + "recording_protection": false, + "performance_monitoring": false + } + }, + { + "timestamp": "2025-08-16T17:55:33.291929", + "level": "info", + "event_type": "udp_streaming_stopped", + "message": "UDP streaming to PlotJuggler stopped (CSV recording continues)", + "details": {} + }, + { + "timestamp": "2025-08-16T17:55:33.835152", + "level": "info", + "event_type": "dataset_deactivated", + "message": "Dataset deactivated: Fast", + "details": { + "dataset_id": "Fast" + } + }, + { + "timestamp": "2025-08-16T17:55:33.945620", + "level": "info", + "event_type": "dataset_deactivated", + "message": "Dataset deactivated: DAR", + "details": { + "dataset_id": "DAR" + } + }, + { + "timestamp": "2025-08-16T17:55:33.958575", + "level": "info", + "event_type": "dataset_deactivated", + "message": "Dataset deactivated: test", + "details": { + "dataset_id": "Test" + } + }, + { + "timestamp": "2025-08-16T17:55:33.972570", + "level": "info", + "event_type": "plc_disconnection", + "message": "Disconnected from PLC 10.1.33.11 (stopped recording and streaming)", + "details": {} + }, + { + "timestamp": "2025-08-16T18:00:44.230305", + "level": "info", + "event_type": "application_started", + "message": "Application initialization completed successfully", + "details": {} + }, + { + "timestamp": "2025-08-16T18:01:59.976168", + "level": "info", + "event_type": "plot_session_created", + "message": "Plot session 'UR29' created and started", + "details": { + "session_id": "plot_1_1755360119976_2", + "variables": [ + "UR29_Brix", + "UR29_ma", + "AUX Blink_1.0S", + "AUX Blink_1.6S" + ], + "time_window": 36, + "trigger_variable": null, + "auto_started": true + } + }, + { + "timestamp": "2025-08-16T18:02:35.827867", + "level": "info", + "event_type": "udp_streaming_stopped", + "message": "UDP streaming to PlotJuggler stopped (CSV recording continues)", + "details": {} + }, + { + "timestamp": "2025-08-16T18:02:35.840125", + "level": "info", + "event_type": "csv_recording_stopped", + "message": "🔥 CRITICAL: CSV recording stopped (dataset threads continue for UDP streaming)", + "details": { + "recording_protection": false, + "performance_monitoring": false + } + }, + { + "timestamp": "2025-08-16T18:02:35.854551", + "level": "info", + "event_type": "udp_streaming_stopped", + "message": "UDP streaming to PlotJuggler stopped (CSV recording continues)", + "details": {} + }, + { + "timestamp": "2025-08-16T18:02:35.867423", + "level": "info", + "event_type": "dataset_deactivated", + "message": "Dataset deactivated: Fast", + "details": { + "dataset_id": "Fast" + } + }, + { + "timestamp": "2025-08-16T18:02:35.881419", + "level": "info", + "event_type": "dataset_deactivated", + "message": "Dataset deactivated: test", + "details": { + "dataset_id": "Test" + } + }, + { + "timestamp": "2025-08-16T18:02:35.895463", + "level": "info", + "event_type": "dataset_deactivated", + "message": "Dataset deactivated: DAR", + "details": { + "dataset_id": "DAR" + } + }, + { + "timestamp": "2025-08-16T18:02:35.908710", + "level": "info", + "event_type": "plc_disconnection", + "message": "Disconnected from PLC 10.1.33.11 (stopped recording and streaming)", + "details": {} + }, + { + "timestamp": "2025-08-16T18:02:46.128780", + "level": "info", + "event_type": "application_started", + "message": "Application initialization completed successfully", + "details": {} + }, + { + "timestamp": "2025-08-16T18:06:55.335011", + "level": "info", + "event_type": "udp_streaming_stopped", + "message": "UDP streaming to PlotJuggler stopped (CSV recording continues)", + "details": {} + }, + { + "timestamp": "2025-08-16T18:06:55.349592", + "level": "info", + "event_type": "csv_recording_stopped", + "message": "🔥 CRITICAL: CSV recording stopped (dataset threads continue for UDP streaming)", + "details": { + "recording_protection": false, + "performance_monitoring": false + } + }, + { + "timestamp": "2025-08-16T18:06:55.363606", + "level": "info", + "event_type": "udp_streaming_stopped", + "message": "UDP streaming to PlotJuggler stopped (CSV recording continues)", + "details": {} + }, + { + "timestamp": "2025-08-16T18:06:55.376630", + "level": "info", + "event_type": "dataset_deactivated", + "message": "Dataset deactivated: Fast", + "details": { + "dataset_id": "Fast" + } + }, + { + "timestamp": "2025-08-16T18:06:55.392695", + "level": "info", + "event_type": "dataset_deactivated", + "message": "Dataset deactivated: DAR", + "details": { + "dataset_id": "DAR" + } + }, + { + "timestamp": "2025-08-16T18:06:55.406337", + "level": "info", + "event_type": "dataset_deactivated", + "message": "Dataset deactivated: test", + "details": { + "dataset_id": "Test" + } + }, + { + "timestamp": "2025-08-16T18:06:55.420713", + "level": "info", + "event_type": "plc_disconnection", + "message": "Disconnected from PLC 10.1.33.11 (stopped recording and streaming)", + "details": {} + }, + { + "timestamp": "2025-08-16T18:07:07.885319", + "level": "info", + "event_type": "application_started", + "message": "Application initialization completed successfully", + "details": {} + }, + { + "timestamp": "2025-08-16T18:07:28.351306", + "level": "info", + "event_type": "udp_streaming_stopped", + "message": "UDP streaming to PlotJuggler stopped (CSV recording continues)", + "details": {} + }, + { + "timestamp": "2025-08-16T18:07:28.367798", + "level": "info", + "event_type": "csv_recording_stopped", + "message": "🔥 CRITICAL: CSV recording stopped (dataset threads continue for UDP streaming)", + "details": { + "recording_protection": false, + "performance_monitoring": false + } + }, + { + "timestamp": "2025-08-16T18:07:28.393690", + "level": "info", + "event_type": "udp_streaming_stopped", + "message": "UDP streaming to PlotJuggler stopped (CSV recording continues)", + "details": {} + }, + { + "timestamp": "2025-08-16T18:07:28.420822", + "level": "info", + "event_type": "dataset_deactivated", + "message": "Dataset deactivated: Fast", + "details": { + "dataset_id": "Fast" + } + }, + { + "timestamp": "2025-08-16T18:07:28.444904", + "level": "info", + "event_type": "dataset_deactivated", + "message": "Dataset deactivated: DAR", + "details": { + "dataset_id": "DAR" + } + }, + { + "timestamp": "2025-08-16T18:07:28.471738", + "level": "info", + "event_type": "dataset_deactivated", + "message": "Dataset deactivated: test", + "details": { + "dataset_id": "Test" + } + }, + { + "timestamp": "2025-08-16T18:07:28.490132", + "level": "info", + "event_type": "plc_disconnection", + "message": "Disconnected from PLC 10.1.33.11 (stopped recording and streaming)", + "details": {} + }, + { + "timestamp": "2025-08-16T18:08:52.243921", + "level": "info", + "event_type": "application_started", + "message": "Application initialization completed successfully", + "details": {} + }, + { + "timestamp": "2025-08-16T18:08:54.594696", + "level": "info", + "event_type": "dataset_activated", + "message": "Dataset activated: DAR", + "details": { + "dataset_id": "DAR", + "variables_count": 2, + "streaming_count": 2, + "prefix": "gateway_phoenix" + } + }, + { + "timestamp": "2025-08-16T18:08:54.617597", + "level": "info", + "event_type": "dataset_activated", + "message": "Dataset activated: Fast", + "details": { + "dataset_id": "Fast", + "variables_count": 2, + "streaming_count": 2, + "prefix": "fast" + } + }, + { + "timestamp": "2025-08-16T18:08:54.634112", + "level": "info", + "event_type": "csv_recording_started", + "message": "🔥 CRITICAL PRIORITY: CSV recording started with MAXIMUM PRIORITY and performance monitoring: 2 datasets activated", + "details": { + "activated_datasets": 2, + "total_datasets": 3, + "priority": "CRITICAL", + "recording_protection": true, + "performance_monitoring": true + } + }, + { + "timestamp": "2025-08-16T18:08:54.653130", + "level": "info", + "event_type": "plc_connection", + "message": "Successfully connected to PLC 10.1.33.11 and auto-started CSV recording for 3 datasets", + "details": { + "ip": "10.1.33.11", + "rack": 0, + "slot": 2, + "symbols_path": "C:/Users/migue/Downloads/symSAE452.asc", + "auto_started_recording": true, + "recording_datasets": 3, + "dataset_names": [ + "test", + "Fast", + "DAR" + ] + } + }, + { + "timestamp": "2025-08-16T18:09:04.594218", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 36 points saved, 0 lost, 0.0% CPU", + "details": { + "duration": 13.355351448059082, + "points_saved": 36, + "points_rate": 2.695548682489508, + "variables_saved": 72, + "udp_points_sent": 0, + "points_lost": 0, + "cpu_average": 0.0, + "cpu_max": 0.0, + "delay_average": 0.0, + "delay_max": 0.0, + "read_errors": 0, + "csv_errors": 0, + "udp_errors": 0, + "read_time_avg": 0.07478510671191746, + "csv_write_time_avg": 0.0008287827173868815 + } + }, + { + "timestamp": "2025-08-16T18:09:09.869658", + "level": "info", + "event_type": "plot_session_created", + "message": "Plot session 'UR29' created and started", + "details": { + "session_id": "plot_1_1755360549868_2", + "variables": [ + "UR29_Brix", + "UR29_ma", + "AUX Blink_1.0S", + "AUX Blink_1.6S" + ], + "time_window": 36, + "trigger_variable": null, + "auto_started": true + } + }, + { + "timestamp": "2025-08-16T18:09:14.628840", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 36 points saved, 0 lost, 0.2% CPU", + "details": { + "duration": 10.034621953964233, + "points_saved": 36, + "points_rate": 3.5875791001551383, + "variables_saved": 72, + "udp_points_sent": 0, + "points_lost": 0, + "cpu_average": 0.2, + "cpu_max": 0.2, + "delay_average": 0.0, + "delay_max": 0.0, + "read_errors": 0, + "csv_errors": 0, + "udp_errors": 0, + "read_time_avg": 0.10597432321972317, + "csv_write_time_avg": 0.00024400817023383247 + } + }, + { + "timestamp": "2025-08-16T18:09:24.664064", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 35 points saved, 0 lost, 1.4% CPU", + "details": { + "duration": 10.035223245620728, + "points_saved": 35, + "points_rate": 3.4877151353133726, + "variables_saved": 70, + "udp_points_sent": 0, + "points_lost": 0, + "cpu_average": 1.4, + "cpu_max": 1.4, + "delay_average": 0.0, + "delay_max": 0.0, + "read_errors": 0, + "csv_errors": 0, + "udp_errors": 0, + "read_time_avg": 0.10966954912458148, + "csv_write_time_avg": 9.672982352120535e-06 + } + }, + { + "timestamp": "2025-08-16T18:09:34.689052", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 36 points saved, 0 lost, 0.3% CPU", + "details": { + "duration": 10.024988651275635, + "points_saved": 36, + "points_rate": 3.591026509084293, + "variables_saved": 72, + "udp_points_sent": 0, + "points_lost": 0, + "cpu_average": 0.3, + "cpu_max": 0.3, + "delay_average": 0.0, + "delay_max": 0.0, + "read_errors": 0, + "csv_errors": 0, + "udp_errors": 0, + "read_time_avg": 0.10865267780092028, + "csv_write_time_avg": 0.0 + } + }, + { + "timestamp": "2025-08-16T18:09:44.711185", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 35 points saved, 0 lost, 0.3% CPU", + "details": { + "duration": 10.021626234054565, + "points_saved": 35, + "points_rate": 3.492447152046664, + "variables_saved": 70, + "udp_points_sent": 0, + "points_lost": 0, + "cpu_average": 0.3, + "cpu_max": 0.3, + "delay_average": 0.0, + "delay_max": 0.0, + "read_errors": 0, + "csv_errors": 0, + "udp_errors": 0, + "read_time_avg": 0.11189383779253279, + "csv_write_time_avg": 1.2377330235072544e-05 + } + }, + { + "timestamp": "2025-08-16T18:09:45.994337", + "level": "info", + "event_type": "udp_streaming_stopped", + "message": "UDP streaming to PlotJuggler stopped (CSV recording continues)", + "details": {} + }, + { + "timestamp": "2025-08-16T18:09:48.019510", + "level": "info", + "event_type": "csv_recording_stopped", + "message": "🔥 CRITICAL: CSV recording stopped (dataset threads continue for UDP streaming)", + "details": { + "recording_protection": false, + "performance_monitoring": false + } + }, + { + "timestamp": "2025-08-16T18:09:48.037352", + "level": "info", + "event_type": "udp_streaming_stopped", + "message": "UDP streaming to PlotJuggler stopped (CSV recording continues)", + "details": {} + }, + { + "timestamp": "2025-08-16T18:09:48.061680", + "level": "info", + "event_type": "dataset_deactivated", + "message": "Dataset deactivated: test", + "details": { + "dataset_id": "Test" + } + }, + { + "timestamp": "2025-08-16T18:09:48.594707", + "level": "info", + "event_type": "dataset_deactivated", + "message": "Dataset deactivated: Fast", + "details": { + "dataset_id": "Fast" + } + }, + { + "timestamp": "2025-08-16T18:09:48.704248", + "level": "info", + "event_type": "dataset_deactivated", + "message": "Dataset deactivated: DAR", + "details": { + "dataset_id": "DAR" + } + }, + { + "timestamp": "2025-08-16T18:09:48.731607", + "level": "info", + "event_type": "plc_disconnection", + "message": "Disconnected from PLC 10.1.33.11 (stopped recording and streaming)", + "details": {} + }, + { + "timestamp": "2025-08-16T18:09:54.026179", + "level": "info", + "event_type": "application_started", + "message": "Application initialization completed successfully", + "details": {} + }, + { + "timestamp": "2025-08-16T18:12:35.193846", + "level": "info", + "event_type": "dataset_activated", + "message": "Dataset activated: DAR", + "details": { + "dataset_id": "DAR", + "variables_count": 2, + "streaming_count": 2, + "prefix": "gateway_phoenix" + } + }, + { + "timestamp": "2025-08-16T18:12:35.214164", + "level": "info", + "event_type": "dataset_activated", + "message": "Dataset activated: Fast", + "details": { + "dataset_id": "Fast", + "variables_count": 2, + "streaming_count": 2, + "prefix": "fast" + } + }, + { + "timestamp": "2025-08-16T18:12:35.242172", + "level": "info", + "event_type": "csv_recording_started", + "message": "🔥 CRITICAL PRIORITY: CSV recording started with MAXIMUM PRIORITY and performance monitoring: 2 datasets activated", + "details": { + "activated_datasets": 2, + "total_datasets": 3, + "priority": "CRITICAL", + "recording_protection": true, + "performance_monitoring": true + } + }, + { + "timestamp": "2025-08-16T18:12:35.264006", + "level": "info", + "event_type": "plc_connection", + "message": "Successfully connected to PLC 10.1.33.11 and auto-started CSV recording for 3 datasets", + "details": { + "ip": "10.1.33.11", + "rack": 0, + "slot": 2, + "symbols_path": "C:/Users/migue/Downloads/symSAE452.asc", + "auto_started_recording": true, + "recording_datasets": 3, + "dataset_names": [ + "DAR", + "Fast", + "test" + ] + } + }, + { + "timestamp": "2025-08-16T18:12:45.194277", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 36 points saved, 0 lost, 0.0% CPU", + "details": { + "duration": 172.17324900627136, + "points_saved": 36, + "points_rate": 0.20909171551202307, + "variables_saved": 72, + "udp_points_sent": 0, + "points_lost": 0, + "cpu_average": 0.0, + "cpu_max": 0.0, + "delay_average": 0.0, + "delay_max": 0.0, + "read_errors": 0, + "csv_errors": 0, + "udp_errors": 0, + "read_time_avg": 0.07627265320883857, + "csv_write_time_avg": 0.0006985391889299665 + } + }, + { + "timestamp": "2025-08-16T18:12:55.217766", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 36 points saved, 0 lost, 0.2% CPU", + "details": { + "duration": 10.023489236831665, + "points_saved": 36, + "points_rate": 3.5915636909866406, + "variables_saved": 72, + "udp_points_sent": 0, + "points_lost": 0, + "cpu_average": 0.2, + "cpu_max": 0.2, + "delay_average": 0.0, + "delay_max": 0.0, + "read_errors": 0, + "csv_errors": 0, + "udp_errors": 0, + "read_time_avg": 0.11325633525848389, + "csv_write_time_avg": 9.622838762071398e-06 + } + }, + { + "timestamp": "2025-08-16T18:13:05.245625", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 35 points saved, 0 lost, 0.0% CPU", + "details": { + "duration": 10.027859687805176, + "points_saved": 35, + "points_rate": 3.490276199472885, + "variables_saved": 70, + "udp_points_sent": 0, + "points_lost": 0, + "cpu_average": 0.0, + "cpu_max": 0.0, + "delay_average": 0.0, + "delay_max": 0.0, + "read_errors": 0, + "csv_errors": 0, + "udp_errors": 0, + "read_time_avg": 0.11114109584263393, + "csv_write_time_avg": 4.802431379045759e-06 + } + }, + { + "timestamp": "2025-08-16T18:13:11.169608", + "level": "info", + "event_type": "udp_streaming_started", + "message": "UDP streaming to PlotJuggler started", + "details": { + "udp_host": "127.0.0.1", + "udp_port": 9870, + "datasets_available": 3 + } + }, + { + "timestamp": "2025-08-16T18:13:15.286578", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 36 points saved, 0 lost, 0.2% CPU", + "details": { + "duration": 10.040952205657959, + "points_saved": 36, + "points_rate": 3.585317334715967, + "variables_saved": 72, + "udp_points_sent": 28, + "points_lost": 0, + "cpu_average": 0.2, + "cpu_max": 0.2, + "delay_average": 0.0, + "delay_max": 0.0, + "read_errors": 0, + "csv_errors": 0, + "udp_errors": 0, + "read_time_avg": 0.11712222629123265, + "csv_write_time_avg": 5.404154459635417e-06 + } + }, + { + "timestamp": "2025-08-16T18:13:25.324111", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 36 points saved, 0 lost, 0.6% CPU", + "details": { + "duration": 10.037533283233643, + "points_saved": 36, + "points_rate": 3.5865385433025847, + "variables_saved": 72, + "udp_points_sent": 72, + "points_lost": 0, + "cpu_average": 0.6, + "cpu_max": 0.6, + "delay_average": 0.0, + "delay_max": 0.0, + "read_errors": 0, + "csv_errors": 0, + "udp_errors": 0, + "read_time_avg": 0.1134060952398512, + "csv_write_time_avg": 1.1357996198866102e-05 + } + }, + { + "timestamp": "2025-08-16T18:13:35.353198", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 35 points saved, 0 lost, 0.0% CPU", + "details": { + "duration": 10.029086589813232, + "points_saved": 35, + "points_rate": 3.489849218726487, + "variables_saved": 70, + "udp_points_sent": 70, + "points_lost": 0, + "cpu_average": 0.0, + "cpu_max": 0.0, + "delay_average": 0.0, + "delay_max": 0.0, + "read_errors": 0, + "csv_errors": 0, + "udp_errors": 0, + "read_time_avg": 0.11029632432120187, + "csv_write_time_avg": 4.945482526506697e-06 + } + }, + { + "timestamp": "2025-08-16T18:13:45.385301", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 36 points saved, 0 lost, 0.2% CPU", + "details": { + "duration": 10.032102823257446, + "points_saved": 36, + "points_rate": 3.5884799661882574, + "variables_saved": 72, + "udp_points_sent": 72, + "points_lost": 0, + "cpu_average": 0.2, + "cpu_max": 0.2, + "delay_average": 0.0, + "delay_max": 0.0, + "read_errors": 0, + "csv_errors": 0, + "udp_errors": 0, + "read_time_avg": 0.10879535145229763, + "csv_write_time_avg": 5.525350570678711e-05 + } + }, + { + "timestamp": "2025-08-16T18:13:55.414956", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 35 points saved, 0 lost, 0.2% CPU", + "details": { + "duration": 10.029655456542969, + "points_saved": 35, + "points_rate": 3.4896512798121417, + "variables_saved": 70, + "udp_points_sent": 70, + "points_lost": 0, + "cpu_average": 0.2, + "cpu_max": 0.2, + "delay_average": 0.0, + "delay_max": 0.0, + "read_errors": 0, + "csv_errors": 0, + "udp_errors": 0, + "read_time_avg": 0.11340193748474121, + "csv_write_time_avg": 4.182543073381697e-06 + } + }, + { + "timestamp": "2025-08-16T18:14:05.434624", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 36 points saved, 0 lost, 0.3% CPU", + "details": { + "duration": 10.019159078598022, + "points_saved": 36, + "points_rate": 3.593115920965841, + "variables_saved": 72, + "udp_points_sent": 72, + "points_lost": 0, + "cpu_average": 0.3, + "cpu_max": 0.3, + "delay_average": 0.0, + "delay_max": 0.0, + "read_errors": 0, + "csv_errors": 0, + "udp_errors": 0, + "read_time_avg": 0.1110761629210578, + "csv_write_time_avg": 3.1597084469265406e-05 + } + }, + { + "timestamp": "2025-08-16T18:14:15.473900", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 36 points saved, 0 lost, 0.5% CPU", + "details": { + "duration": 10.039785385131836, + "points_saved": 36, + "points_rate": 3.58573401910695, + "variables_saved": 72, + "udp_points_sent": 72, + "points_lost": 0, + "cpu_average": 0.5, + "cpu_max": 0.5, + "delay_average": 0.0, + "delay_max": 0.0, + "read_errors": 0, + "csv_errors": 0, + "udp_errors": 0, + "read_time_avg": 0.11252274778154162, + "csv_write_time_avg": 5.053149329291449e-06 + } + }, + { + "timestamp": "2025-08-16T18:14:25.509577", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 35 points saved, 0 lost, 0.2% CPU", + "details": { + "duration": 10.035677194595337, + "points_saved": 35, + "points_rate": 3.48755737369164, + "variables_saved": 70, + "udp_points_sent": 70, + "points_lost": 0, + "cpu_average": 0.2, + "cpu_max": 0.2, + "delay_average": 0.0, + "delay_max": 0.0, + "read_errors": 0, + "csv_errors": 0, + "udp_errors": 0, + "read_time_avg": 0.10935754776000976, + "csv_write_time_avg": 0.0 + } + }, + { + "timestamp": "2025-08-16T18:14:35.545532", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 36 points saved, 0 lost, 0.8% CPU", + "details": { + "duration": 10.035954475402832, + "points_saved": 36, + "points_rate": 3.5871027602040813, + "variables_saved": 72, + "udp_points_sent": 72, + "points_lost": 0, + "cpu_average": 0.8, + "cpu_max": 0.8, + "delay_average": 0.0, + "delay_max": 0.0, + "read_errors": 0, + "csv_errors": 0, + "udp_errors": 0, + "read_time_avg": 0.10765999555587769, + "csv_write_time_avg": 2.1682845221625434e-05 + } + }, + { + "timestamp": "2025-08-16T18:14:45.574789", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 36 points saved, 0 lost, 0.0% CPU", + "details": { + "duration": 10.029256820678711, + "points_saved": 36, + "points_rate": 3.5894982692809103, + "variables_saved": 72, + "udp_points_sent": 72, + "points_lost": 0, + "cpu_average": 0.0, + "cpu_max": 0.0, + "delay_average": 0.0, + "delay_max": 0.0, + "read_errors": 0, + "csv_errors": 0, + "udp_errors": 0, + "read_time_avg": 0.10831038819419013, + "csv_write_time_avg": 1.9841723971896703e-05 + } + }, + { + "timestamp": "2025-08-16T18:14:50.541624", + "level": "info", + "event_type": "udp_streaming_stopped", + "message": "UDP streaming to PlotJuggler stopped (CSV recording continues)", + "details": {} + }, + { + "timestamp": "2025-08-16T18:14:52.561333", + "level": "info", + "event_type": "csv_recording_stopped", + "message": "🔥 CRITICAL: CSV recording stopped (dataset threads continue for UDP streaming)", + "details": { + "recording_protection": false, + "performance_monitoring": false + } + }, + { + "timestamp": "2025-08-16T18:14:52.579277", + "level": "info", + "event_type": "udp_streaming_stopped", + "message": "UDP streaming to PlotJuggler stopped (CSV recording continues)", + "details": {} + }, + { + "timestamp": "2025-08-16T18:14:53.063130", + "level": "info", + "event_type": "dataset_deactivated", + "message": "Dataset deactivated: DAR", + "details": { + "dataset_id": "DAR" + } + }, + { + "timestamp": "2025-08-16T18:14:53.250504", + "level": "info", + "event_type": "dataset_deactivated", + "message": "Dataset deactivated: Fast", + "details": { + "dataset_id": "Fast" + } + }, + { + "timestamp": "2025-08-16T18:14:53.266532", + "level": "info", + "event_type": "dataset_deactivated", + "message": "Dataset deactivated: test", + "details": { + "dataset_id": "Test" + } + }, + { + "timestamp": "2025-08-16T18:14:53.283593", + "level": "info", + "event_type": "plc_disconnection", + "message": "Disconnected from PLC 10.1.33.11 (stopped recording and streaming)", + "details": {} + }, + { + "timestamp": "2025-08-16T18:14:58.719086", + "level": "info", + "event_type": "application_started", + "message": "Application initialization completed successfully", + "details": {} + }, + { + "timestamp": "2025-08-16T18:15:09.745453", + "level": "info", + "event_type": "dataset_activated", + "message": "Dataset activated: DAR", + "details": { + "dataset_id": "DAR", + "variables_count": 2, + "streaming_count": 2, + "prefix": "gateway_phoenix" + } + }, + { + "timestamp": "2025-08-16T18:15:09.772485", + "level": "info", + "event_type": "dataset_activated", + "message": "Dataset activated: Fast", + "details": { + "dataset_id": "Fast", + "variables_count": 2, + "streaming_count": 2, + "prefix": "fast" + } + }, + { + "timestamp": "2025-08-16T18:15:09.797139", + "level": "info", + "event_type": "csv_recording_started", + "message": "🔥 CRITICAL PRIORITY: CSV recording started with MAXIMUM PRIORITY and performance monitoring: 2 datasets activated", + "details": { + "activated_datasets": 2, + "total_datasets": 3, + "priority": "CRITICAL", + "recording_protection": true, + "performance_monitoring": true + } + }, + { + "timestamp": "2025-08-16T18:15:09.817144", + "level": "info", + "event_type": "plc_connection", + "message": "Successfully connected to PLC 10.1.33.11 and auto-started CSV recording for 3 datasets", + "details": { + "ip": "10.1.33.11", + "rack": 0, + "slot": 2, + "symbols_path": "C:/Users/migue/Downloads/symSAE452.asc", + "auto_started_recording": true, + "recording_datasets": 3, + "dataset_names": [ + "DAR", + "Fast", + "test" + ] + } + }, + { + "timestamp": "2025-08-16T18:15:19.746228", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 36 points saved, 0 lost, 0.0% CPU", + "details": { + "duration": 22.043440341949463, + "points_saved": 36, + "points_rate": 1.6331389039800062, + "variables_saved": 72, + "udp_points_sent": 0, + "points_lost": 0, + "cpu_average": 0.0, + "cpu_max": 0.0, + "delay_average": 0.0, + "delay_max": 0.0, + "read_errors": 0, + "csv_errors": 0, + "udp_errors": 0, + "read_time_avg": 0.07398335138956706, + "csv_write_time_avg": 0.00012909344264439175 + } + }, + { + "timestamp": "2025-08-16T18:15:29.770773", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 36 points saved, 0 lost, 0.3% CPU", + "details": { + "duration": 10.024544954299927, + "points_saved": 36, + "points_rate": 3.591185451720496, + "variables_saved": 72, + "udp_points_sent": 0, + "points_lost": 0, + "cpu_average": 0.3, + "cpu_max": 0.3, + "delay_average": 0.0, + "delay_max": 0.0, + "read_errors": 0, + "csv_errors": 0, + "udp_errors": 0, + "read_time_avg": 0.10564761691623265, + "csv_write_time_avg": 3.854433695475261e-06 + } + }, + { + "timestamp": "2025-08-16T18:15:38.837357", + "level": "info", + "event_type": "udp_streaming_stopped", + "message": "UDP streaming to PlotJuggler stopped (CSV recording continues)", + "details": {} + }, + { + "timestamp": "2025-08-16T18:15:39.801524", + "level": "info", + "event_type": "csv_recording_stopped", + "message": "🔥 CRITICAL: CSV recording stopped (dataset threads continue for UDP streaming)", + "details": { + "recording_protection": false, + "performance_monitoring": false + } + }, + { + "timestamp": "2025-08-16T18:15:39.819009", + "level": "info", + "event_type": "udp_streaming_stopped", + "message": "UDP streaming to PlotJuggler stopped (CSV recording continues)", + "details": {} + }, + { + "timestamp": "2025-08-16T18:15:40.316145", + "level": "info", + "event_type": "dataset_deactivated", + "message": "Dataset deactivated: DAR", + "details": { + "dataset_id": "DAR" + } + }, + { + "timestamp": "2025-08-16T18:15:40.473755", + "level": "info", + "event_type": "dataset_deactivated", + "message": "Dataset deactivated: Fast", + "details": { + "dataset_id": "Fast" + } + }, + { + "timestamp": "2025-08-16T18:15:40.487765", + "level": "info", + "event_type": "dataset_deactivated", + "message": "Dataset deactivated: test", + "details": { + "dataset_id": "Test" + } + }, + { + "timestamp": "2025-08-16T18:15:40.502765", + "level": "info", + "event_type": "plc_disconnection", + "message": "Disconnected from PLC 10.1.33.11 (application shutdown (will auto-reconnect on restart))", + "details": {} + }, + { + "timestamp": "2025-08-16T18:15:47.739844", + "level": "info", + "event_type": "application_started", + "message": "Application initialization completed successfully", + "details": {} + }, + { + "timestamp": "2025-08-16T18:15:47.789389", + "level": "info", + "event_type": "dataset_activated", + "message": "Dataset activated: DAR", + "details": { + "dataset_id": "DAR", + "variables_count": 2, + "streaming_count": 2, + "prefix": "gateway_phoenix" + } + }, + { + "timestamp": "2025-08-16T18:15:47.805386", + "level": "info", + "event_type": "dataset_activated", + "message": "Dataset activated: Fast", + "details": { + "dataset_id": "Fast", + "variables_count": 2, + "streaming_count": 2, + "prefix": "fast" + } + }, + { + "timestamp": "2025-08-16T18:15:47.821386", + "level": "info", + "event_type": "csv_recording_started", + "message": "🔥 CRITICAL PRIORITY: CSV recording started with MAXIMUM PRIORITY and performance monitoring: 2 datasets activated", + "details": { + "activated_datasets": 2, + "total_datasets": 3, + "priority": "CRITICAL", + "recording_protection": true, + "performance_monitoring": true + } + }, + { + "timestamp": "2025-08-16T18:15:57.789677", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 36 points saved, 0 lost, 0.0% CPU", + "details": { + "duration": 11.05662226676941, + "points_saved": 36, + "points_rate": 3.2559672503416994, + "variables_saved": 72, + "udp_points_sent": 0, + "points_lost": 0, + "cpu_average": 0.0, + "cpu_max": 0.0, + "delay_average": 0.0, + "delay_max": 0.0, + "read_errors": 0, + "csv_errors": 0, + "udp_errors": 0, + "read_time_avg": 0.04439822170469496, + "csv_write_time_avg": 0.00016028351253933378 + } + }, + { + "timestamp": "2025-08-16T18:16:07.805238", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 37 points saved, 0 lost, 0.6% CPU", + "details": { + "duration": 10.015561580657959, + "points_saved": 37, + "points_rate": 3.694251161258332, + "variables_saved": 74, + "udp_points_sent": 0, + "points_lost": 0, + "cpu_average": 0.6, + "cpu_max": 0.6, + "delay_average": 0.0, + "delay_max": 0.0, + "read_errors": 0, + "csv_errors": 0, + "udp_errors": 0, + "read_time_avg": 0.03554723069474504, + "csv_write_time_avg": 2.2488671380120353e-06 + } + }, + { + "timestamp": "2025-08-16T18:16:17.821970", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 36 points saved, 0 lost, 0.0% CPU", + "details": { + "duration": 10.01673150062561, + "points_saved": 36, + "points_rate": 3.5939867208930942, + "variables_saved": 72, + "udp_points_sent": 0, + "points_lost": 0, + "cpu_average": 0.0, + "cpu_max": 0.0, + "delay_average": 0.0, + "delay_max": 0.0, + "read_errors": 0, + "csv_errors": 0, + "udp_errors": 0, + "read_time_avg": 0.03927622238794962, + "csv_write_time_avg": 0.0 + } + }, + { + "timestamp": "2025-08-16T18:16:27.837370", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 36 points saved, 0 lost, 0.2% CPU", + "details": { + "duration": 10.015400409698486, + "points_saved": 36, + "points_rate": 3.594464377593844, + "variables_saved": 72, + "udp_points_sent": 0, + "points_lost": 0, + "cpu_average": 0.2, + "cpu_max": 0.2, + "delay_average": 0.0, + "delay_max": 0.0, + "read_errors": 0, + "csv_errors": 0, + "udp_errors": 0, + "read_time_avg": 0.04052731063630846, + "csv_write_time_avg": 0.0 + } + }, + { + "timestamp": "2025-08-16T18:16:37.854374", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 36 points saved, 0 lost, 0.0% CPU", + "details": { + "duration": 10.017004013061523, + "points_saved": 36, + "points_rate": 3.593888946541135, + "variables_saved": 72, + "udp_points_sent": 0, + "points_lost": 0, + "cpu_average": 0.0, + "cpu_max": 0.0, + "delay_average": 0.0, + "delay_max": 0.0, + "read_errors": 0, + "csv_errors": 0, + "udp_errors": 0, + "read_time_avg": 0.03979142506917318, + "csv_write_time_avg": 0.0 + } + }, + { + "timestamp": "2025-08-16T18:16:47.870105", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 36 points saved, 0 lost, 0.3% CPU", + "details": { + "duration": 10.015730619430542, + "points_saved": 36, + "points_rate": 3.5943458712996845, + "variables_saved": 72, + "udp_points_sent": 0, + "points_lost": 0, + "cpu_average": 0.3, + "cpu_max": 0.3, + "delay_average": 0.0, + "delay_max": 0.0, + "read_errors": 0, + "csv_errors": 0, + "udp_errors": 0, + "read_time_avg": 0.03612257374657525, + "csv_write_time_avg": 0.0 + } + }, + { + "timestamp": "2025-08-16T18:16:57.885474", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 36 points saved, 0 lost, 0.3% CPU", + "details": { + "duration": 10.015369653701782, + "points_saved": 36, + "points_rate": 3.594475415762017, + "variables_saved": 72, + "udp_points_sent": 0, + "points_lost": 0, + "cpu_average": 0.3, + "cpu_max": 0.3, + "delay_average": 0.0, + "delay_max": 0.0, + "read_errors": 0, + "csv_errors": 0, + "udp_errors": 0, + "read_time_avg": 0.04104538758595785, + "csv_write_time_avg": 0.0 + } + }, + { + "timestamp": "2025-08-16T18:17:07.902040", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 36 points saved, 0 lost, 0.3% CPU", + "details": { + "duration": 10.016565561294556, + "points_saved": 36, + "points_rate": 3.5940462606373944, + "variables_saved": 72, + "udp_points_sent": 0, + "points_lost": 0, + "cpu_average": 0.3, + "cpu_max": 0.3, + "delay_average": 0.0, + "delay_max": 0.0, + "read_errors": 0, + "csv_errors": 0, + "udp_errors": 0, + "read_time_avg": 0.04232439729902479, + "csv_write_time_avg": 0.0 + } + }, + { + "timestamp": "2025-08-16T18:17:17.917923", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 36 points saved, 0 lost, 0.2% CPU", + "details": { + "duration": 10.015883445739746, + "points_saved": 36, + "points_rate": 3.5942910273494237, + "variables_saved": 72, + "udp_points_sent": 0, + "points_lost": 0, + "cpu_average": 0.2, + "cpu_max": 0.2, + "delay_average": 0.0, + "delay_max": 0.0, + "read_errors": 0, + "csv_errors": 0, + "udp_errors": 0, + "read_time_avg": 0.03648039367463854, + "csv_write_time_avg": 0.0 + } + }, + { + "timestamp": "2025-08-16T18:17:27.933485", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 37 points saved, 0 lost, 0.2% CPU", + "details": { + "duration": 10.01556134223938, + "points_saved": 37, + "points_rate": 3.6942512491992954, + "variables_saved": 74, + "udp_points_sent": 0, + "points_lost": 0, + "cpu_average": 0.2, + "cpu_max": 0.2, + "delay_average": 0.0, + "delay_max": 0.0, + "read_errors": 0, + "csv_errors": 0, + "udp_errors": 0, + "read_time_avg": 0.03906994896966058, + "csv_write_time_avg": 3.0524021870381124e-05 + } + }, + { + "timestamp": "2025-08-16T18:17:37.949275", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 36 points saved, 0 lost, 0.3% CPU", + "details": { + "duration": 10.015790224075317, + "points_saved": 36, + "points_rate": 3.594324481104396, + "variables_saved": 72, + "udp_points_sent": 0, + "points_lost": 0, + "cpu_average": 0.3, + "cpu_max": 0.3, + "delay_average": 0.0, + "delay_max": 0.0, + "read_errors": 0, + "csv_errors": 0, + "udp_errors": 0, + "read_time_avg": 0.03867859310574002, + "csv_write_time_avg": 0.0 + } + }, + { + "timestamp": "2025-08-16T18:17:47.965127", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 36 points saved, 0 lost, 0.2% CPU", + "details": { + "duration": 10.015851974487305, + "points_saved": 36, + "points_rate": 3.594302321130578, + "variables_saved": 72, + "udp_points_sent": 0, + "points_lost": 0, + "cpu_average": 0.2, + "cpu_max": 0.2, + "delay_average": 0.0, + "delay_max": 0.0, + "read_errors": 0, + "csv_errors": 0, + "udp_errors": 0, + "read_time_avg": 0.03987422916624281, + "csv_write_time_avg": 0.0 + } + }, + { + "timestamp": "2025-08-16T18:17:57.980939", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 36 points saved, 0 lost, 0.0% CPU", + "details": { + "duration": 10.015811681747437, + "points_saved": 36, + "points_rate": 3.5943167806964156, + "variables_saved": 72, + "udp_points_sent": 0, + "points_lost": 0, + "cpu_average": 0.0, + "cpu_max": 0.0, + "delay_average": 0.0, + "delay_max": 0.0, + "read_errors": 0, + "csv_errors": 0, + "udp_errors": 0, + "read_time_avg": 0.037962251239352755, + "csv_write_time_avg": 0.0 + } + }, + { + "timestamp": "2025-08-16T18:18:07.997921", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 36 points saved, 0 lost, 0.0% CPU", + "details": { + "duration": 10.016981840133667, + "points_saved": 36, + "points_rate": 3.5938969017357842, + "variables_saved": 72, + "udp_points_sent": 0, + "points_lost": 0, + "cpu_average": 0.0, + "cpu_max": 0.0, + "delay_average": 0.0, + "delay_max": 0.0, + "read_errors": 0, + "csv_errors": 0, + "udp_errors": 0, + "read_time_avg": 0.040401822990841336, + "csv_write_time_avg": 0.0 + } + }, + { + "timestamp": "2025-08-16T18:18:18.014167", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 36 points saved, 0 lost, 0.2% CPU", + "details": { + "duration": 10.016246557235718, + "points_saved": 36, + "points_rate": 3.5941607262047346, + "variables_saved": 72, + "udp_points_sent": 0, + "points_lost": 0, + "cpu_average": 0.2, + "cpu_max": 0.2, + "delay_average": 0.0, + "delay_max": 0.0, + "read_errors": 0, + "csv_errors": 0, + "udp_errors": 0, + "read_time_avg": 0.03960382276111179, + "csv_write_time_avg": 0.0 + } + }, + { + "timestamp": "2025-08-16T18:18:28.029038", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 36 points saved, 0 lost, 0.2% CPU", + "details": { + "duration": 10.014870882034302, + "points_saved": 36, + "points_rate": 3.5946544317990634, + "variables_saved": 72, + "udp_points_sent": 0, + "points_lost": 0, + "cpu_average": 0.2, + "cpu_max": 0.2, + "delay_average": 0.0, + "delay_max": 0.0, + "read_errors": 0, + "csv_errors": 0, + "udp_errors": 0, + "read_time_avg": 0.03836107916302151, + "csv_write_time_avg": 0.0 + } + }, + { + "timestamp": "2025-08-16T18:18:38.046633", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 37 points saved, 0 lost, 0.0% CPU", + "details": { + "duration": 10.017594814300537, + "points_saved": 37, + "points_rate": 3.693501352957593, + "variables_saved": 74, + "udp_points_sent": 0, + "points_lost": 0, + "cpu_average": 0.0, + "cpu_max": 0.0, + "delay_average": 0.0, + "delay_max": 0.0, + "read_errors": 0, + "csv_errors": 0, + "udp_errors": 0, + "read_time_avg": 0.04004202017912994, + "csv_write_time_avg": 0.0 + } + }, + { + "timestamp": "2025-08-16T18:18:48.062480", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 36 points saved, 0 lost, 0.0% CPU", + "details": { + "duration": 10.015847206115723, + "points_saved": 36, + "points_rate": 3.594304032315732, + "variables_saved": 72, + "udp_points_sent": 0, + "points_lost": 0, + "cpu_average": 0.0, + "cpu_max": 0.0, + "delay_average": 0.0, + "delay_max": 0.0, + "read_errors": 0, + "csv_errors": 0, + "udp_errors": 0, + "read_time_avg": 0.03702466355429755, + "csv_write_time_avg": 0.0 + } + }, + { + "timestamp": "2025-08-16T18:18:58.077999", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 36 points saved, 0 lost, 0.2% CPU", + "details": { + "duration": 10.0155189037323, + "points_saved": 36, + "points_rate": 3.594421851331591, + "variables_saved": 72, + "udp_points_sent": 0, + "points_lost": 0, + "cpu_average": 0.2, + "cpu_max": 0.2, + "delay_average": 0.0, + "delay_max": 0.0, + "read_errors": 0, + "csv_errors": 0, + "udp_errors": 0, + "read_time_avg": 0.04394581582811144, + "csv_write_time_avg": 0.0 + } + }, + { + "timestamp": "2025-08-16T18:19:08.094513", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 36 points saved, 0 lost, 0.0% CPU", + "details": { + "duration": 10.016514301300049, + "points_saved": 36, + "points_rate": 3.594064653342285, + "variables_saved": 72, + "udp_points_sent": 0, + "points_lost": 0, + "cpu_average": 0.0, + "cpu_max": 0.0, + "delay_average": 0.0, + "delay_max": 0.0, + "read_errors": 0, + "csv_errors": 0, + "udp_errors": 0, + "read_time_avg": 0.03640420569313897, + "csv_write_time_avg": 0.0 + } + }, + { + "timestamp": "2025-08-16T18:19:18.115813", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 36 points saved, 0 lost, 0.0% CPU", + "details": { + "duration": 10.021299362182617, + "points_saved": 36, + "points_rate": 3.592348526764226, + "variables_saved": 72, + "udp_points_sent": 0, + "points_lost": 0, + "cpu_average": 0.0, + "cpu_max": 0.0, + "delay_average": 0.0, + "delay_max": 0.0, + "read_errors": 0, + "csv_errors": 0, + "udp_errors": 0, + "read_time_avg": 0.03397510449091593, + "csv_write_time_avg": 0.0 + } + }, + { + "timestamp": "2025-08-16T18:19:28.132007", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 36 points saved, 0 lost, 0.0% CPU", + "details": { + "duration": 10.016194581985474, + "points_saved": 36, + "points_rate": 3.5941793767412866, + "variables_saved": 72, + "udp_points_sent": 0, + "points_lost": 0, + "cpu_average": 0.0, + "cpu_max": 0.0, + "delay_average": 0.0, + "delay_max": 0.0, + "read_errors": 0, + "csv_errors": 0, + "udp_errors": 0, + "read_time_avg": 0.033335248629252114, + "csv_write_time_avg": 0.0 + } + }, + { + "timestamp": "2025-08-16T18:19:38.148596", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 36 points saved, 0 lost, 0.3% CPU", + "details": { + "duration": 10.01658844947815, + "points_saved": 36, + "points_rate": 3.5940380481415857, + "variables_saved": 72, + "udp_points_sent": 0, + "points_lost": 0, + "cpu_average": 0.3, + "cpu_max": 0.3, + "delay_average": 0.0, + "delay_max": 0.0, + "read_errors": 0, + "csv_errors": 0, + "udp_errors": 0, + "read_time_avg": 0.03539826472600301, + "csv_write_time_avg": 0.0 + } + }, + { + "timestamp": "2025-08-16T18:19:48.164694", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 36 points saved, 0 lost, 0.2% CPU", + "details": { + "duration": 10.016098737716675, + "points_saved": 36, + "points_rate": 3.5942137695226792, + "variables_saved": 72, + "udp_points_sent": 0, + "points_lost": 0, + "cpu_average": 0.2, + "cpu_max": 0.2, + "delay_average": 0.0, + "delay_max": 0.0, + "read_errors": 0, + "csv_errors": 0, + "udp_errors": 0, + "read_time_avg": 0.03839094771279229, + "csv_write_time_avg": 1.9404623243543838e-06 + } + }, + { + "timestamp": "2025-08-16T18:19:58.180998", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 37 points saved, 0 lost, 0.0% CPU", + "details": { + "duration": 10.016303777694702, + "points_saved": 37, + "points_rate": 3.6939774213313363, + "variables_saved": 74, + "udp_points_sent": 0, + "points_lost": 0, + "cpu_average": 0.0, + "cpu_max": 0.0, + "delay_average": 0.0, + "delay_max": 0.0, + "read_errors": 0, + "csv_errors": 0, + "udp_errors": 0, + "read_time_avg": 0.04166726808290224, + "csv_write_time_avg": 3.5569474503800677e-06 + } + }, + { + "timestamp": "2025-08-16T18:20:08.197365", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 36 points saved, 0 lost, 0.0% CPU", + "details": { + "duration": 10.016367435455322, + "points_saved": 36, + "points_rate": 3.5941173516228457, + "variables_saved": 72, + "udp_points_sent": 0, + "points_lost": 0, + "cpu_average": 0.0, + "cpu_max": 0.0, + "delay_average": 0.0, + "delay_max": 0.0, + "read_errors": 0, + "csv_errors": 0, + "udp_errors": 0, + "read_time_avg": 0.03984416855706109, + "csv_write_time_avg": 0.0 + } + }, + { + "timestamp": "2025-08-16T18:20:18.213931", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 36 points saved, 0 lost, 0.0% CPU", + "details": { + "duration": 10.016565084457397, + "points_saved": 36, + "points_rate": 3.594046431731456, + "variables_saved": 72, + "udp_points_sent": 0, + "points_lost": 0, + "cpu_average": 0.0, + "cpu_max": 0.0, + "delay_average": 0.0, + "delay_max": 0.0, + "read_errors": 0, + "csv_errors": 0, + "udp_errors": 0, + "read_time_avg": 0.03554742866092258, + "csv_write_time_avg": 0.0 + } + }, + { + "timestamp": "2025-08-16T18:20:28.232351", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 36 points saved, 0 lost, 0.3% CPU", + "details": { + "duration": 10.018420934677124, + "points_saved": 36, + "points_rate": 3.593380656964801, + "variables_saved": 72, + "udp_points_sent": 0, + "points_lost": 0, + "cpu_average": 0.3, + "cpu_max": 0.3, + "delay_average": 0.0, + "delay_max": 0.0, + "read_errors": 0, + "csv_errors": 0, + "udp_errors": 0, + "read_time_avg": 0.038087175952063665, + "csv_write_time_avg": 0.0 + } + }, + { + "timestamp": "2025-08-16T18:20:38.249273", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 36 points saved, 0 lost, 0.2% CPU", + "details": { + "duration": 10.016921520233154, + "points_saved": 36, + "points_rate": 3.593918543465045, + "variables_saved": 72, + "udp_points_sent": 0, + "points_lost": 0, + "cpu_average": 0.2, + "cpu_max": 0.2, + "delay_average": 0.0, + "delay_max": 0.0, + "read_errors": 0, + "csv_errors": 0, + "udp_errors": 0, + "read_time_avg": 0.037242107921176486, + "csv_write_time_avg": 0.0 + } + }, + { + "timestamp": "2025-08-16T18:20:48.265814", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 36 points saved, 0 lost, 0.0% CPU", + "details": { + "duration": 10.016541242599487, + "points_saved": 36, + "points_rate": 3.5940549864553146, + "variables_saved": 72, + "udp_points_sent": 0, + "points_lost": 0, + "cpu_average": 0.0, + "cpu_max": 0.0, + "delay_average": 0.0, + "delay_max": 0.0, + "read_errors": 0, + "csv_errors": 0, + "udp_errors": 0, + "read_time_avg": 0.036770641803741455, + "csv_write_time_avg": 2.1060307820638022e-06 + } + }, + { + "timestamp": "2025-08-16T18:20:58.282420", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 36 points saved, 0 lost, 0.2% CPU", + "details": { + "duration": 10.016606092453003, + "points_saved": 36, + "points_rate": 3.5940317177016823, + "variables_saved": 72, + "udp_points_sent": 0, + "points_lost": 0, + "cpu_average": 0.2, + "cpu_max": 0.2, + "delay_average": 0.0, + "delay_max": 0.0, + "read_errors": 0, + "csv_errors": 0, + "udp_errors": 0, + "read_time_avg": 0.03727916876475016, + "csv_write_time_avg": 0.0 + } + }, + { + "timestamp": "2025-08-16T18:21:08.299399", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 36 points saved, 0 lost, 0.0% CPU", + "details": { + "duration": 10.01697850227356, + "points_saved": 36, + "points_rate": 3.593898099295018, + "variables_saved": 72, + "udp_points_sent": 0, + "points_lost": 0, + "cpu_average": 0.0, + "cpu_max": 0.0, + "delay_average": 0.0, + "delay_max": 0.0, + "read_errors": 0, + "csv_errors": 0, + "udp_errors": 0, + "read_time_avg": 0.03724938631057739, + "csv_write_time_avg": 0.0 + } + }, + { + "timestamp": "2025-08-16T18:21:18.315253", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 36 points saved, 0 lost, 0.2% CPU", + "details": { + "duration": 10.015853881835938, + "points_saved": 36, + "points_rate": 3.594301636656972, + "variables_saved": 72, + "udp_points_sent": 0, + "points_lost": 0, + "cpu_average": 0.2, + "cpu_max": 0.2, + "delay_average": 0.0, + "delay_max": 0.0, + "read_errors": 0, + "csv_errors": 0, + "udp_errors": 0, + "read_time_avg": 0.044117622905307345, + "csv_write_time_avg": 8.092986212836371e-06 + } + }, + { + "timestamp": "2025-08-16T18:21:28.354564", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 35 points saved, 0 lost, 0.3% CPU", + "details": { + "duration": 10.03831148147583, + "points_saved": 35, + "points_rate": 3.486642157357555, + "variables_saved": 70, + "udp_points_sent": 0, + "points_lost": 0, + "cpu_average": 0.3, + "cpu_max": 0.3, + "delay_average": 0.0, + "delay_max": 0.0, + "read_errors": 0, + "csv_errors": 0, + "udp_errors": 0, + "read_time_avg": 0.11122162682669504, + "csv_write_time_avg": 2.044950212751116e-05 + } + }, + { + "timestamp": "2025-08-16T18:21:38.413553", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 36 points saved, 0 lost, 0.0% CPU", + "details": { + "duration": 10.059988737106323, + "points_saved": 36, + "points_rate": 3.578532833462706, + "variables_saved": 72, + "udp_points_sent": 0, + "points_lost": 0, + "cpu_average": 0.0, + "cpu_max": 0.0, + "delay_average": 0.0, + "delay_max": 0.0, + "read_errors": 0, + "csv_errors": 0, + "udp_errors": 0, + "read_time_avg": 0.10544510682423909, + "csv_write_time_avg": 3.349781036376953e-05 + } + }, + { + "timestamp": "2025-08-16T18:21:48.447880", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 36 points saved, 0 lost, 0.0% CPU", + "details": { + "duration": 10.034327268600464, + "points_saved": 36, + "points_rate": 3.587684459191562, + "variables_saved": 72, + "udp_points_sent": 0, + "points_lost": 0, + "cpu_average": 0.0, + "cpu_max": 0.0, + "delay_average": 0.0, + "delay_max": 0.0, + "read_errors": 0, + "csv_errors": 0, + "udp_errors": 0, + "read_time_avg": 0.11204698350694445, + "csv_write_time_avg": 3.973642985026042e-06 + } + }, + { + "timestamp": "2025-08-16T18:21:58.480942", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 35 points saved, 0 lost, 0.2% CPU", + "details": { + "duration": 10.033062219619751, + "points_saved": 35, + "points_rate": 3.4884663559204445, + "variables_saved": 70, + "udp_points_sent": 0, + "points_lost": 0, + "cpu_average": 0.2, + "cpu_max": 0.2, + "delay_average": 0.0, + "delay_max": 0.0, + "read_errors": 0, + "csv_errors": 0, + "udp_errors": 0, + "read_time_avg": 0.11097707067217145, + "csv_write_time_avg": 1.735687255859375e-05 + } + }, + { + "timestamp": "2025-08-16T18:22:08.508297", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 36 points saved, 0 lost, 0.3% CPU", + "details": { + "duration": 10.027354955673218, + "points_saved": 36, + "points_rate": 3.5901790810379293, + "variables_saved": 72, + "udp_points_sent": 0, + "points_lost": 0, + "cpu_average": 0.3, + "cpu_max": 0.3, + "delay_average": 0.0, + "delay_max": 0.0, + "read_errors": 0, + "csv_errors": 0, + "udp_errors": 0, + "read_time_avg": 0.11127992471059163, + "csv_write_time_avg": 1.777542961968316e-05 + } + }, + { + "timestamp": "2025-08-16T18:22:18.537710", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 35 points saved, 0 lost, 0.3% CPU", + "details": { + "duration": 10.028420448303223, + "points_saved": 35, + "points_rate": 3.4900810332420686, + "variables_saved": 70, + "udp_points_sent": 0, + "points_lost": 0, + "cpu_average": 0.3, + "cpu_max": 0.3, + "delay_average": 0.0, + "delay_max": 0.0, + "read_errors": 0, + "csv_errors": 0, + "udp_errors": 0, + "read_time_avg": 0.1092137200491769, + "csv_write_time_avg": 0.0 + } + }, + { + "timestamp": "2025-08-16T18:22:28.580719", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 36 points saved, 0 lost, 0.3% CPU", + "details": { + "duration": 10.044001340866089, + "points_saved": 36, + "points_rate": 3.5842289121892668, + "variables_saved": 72, + "udp_points_sent": 0, + "points_lost": 0, + "cpu_average": 0.3, + "cpu_max": 0.3, + "delay_average": 0.0, + "delay_max": 0.0, + "read_errors": 0, + "csv_errors": 0, + "udp_errors": 0, + "read_time_avg": 0.10911467340257433, + "csv_write_time_avg": 1.1616282992892795e-05 + } + }, + { + "timestamp": "2025-08-16T18:22:38.611725", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 36 points saved, 0 lost, 0.0% CPU", + "details": { + "duration": 10.031005620956421, + "points_saved": 36, + "points_rate": 3.5888724780285317, + "variables_saved": 72, + "udp_points_sent": 0, + "points_lost": 0, + "cpu_average": 0.0, + "cpu_max": 0.0, + "delay_average": 0.0, + "delay_max": 0.0, + "read_errors": 0, + "csv_errors": 0, + "udp_errors": 0, + "read_time_avg": 0.11374937825732762, + "csv_write_time_avg": 8.463859558105469e-06 + } + }, + { + "timestamp": "2025-08-16T18:22:48.652697", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 35 points saved, 0 lost, 0.2% CPU", + "details": { + "duration": 10.040971755981445, + "points_saved": 35, + "points_rate": 3.485718399631028, + "variables_saved": 70, + "udp_points_sent": 0, + "points_lost": 0, + "cpu_average": 0.2, + "cpu_max": 0.2, + "delay_average": 0.0, + "delay_max": 0.0, + "read_errors": 0, + "csv_errors": 0, + "udp_errors": 0, + "read_time_avg": 0.10770289557320731, + "csv_write_time_avg": 4.7547476632254465e-06 + } + }, + { + "timestamp": "2025-08-16T18:22:58.687697", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 36 points saved, 0 lost, 0.0% CPU", + "details": { + "duration": 10.035000324249268, + "points_saved": 36, + "points_rate": 3.5874438302714466, + "variables_saved": 72, + "udp_points_sent": 0, + "points_lost": 0, + "cpu_average": 0.0, + "cpu_max": 0.0, + "delay_average": 0.0, + "delay_max": 0.0, + "read_errors": 0, + "csv_errors": 0, + "udp_errors": 0, + "read_time_avg": 0.111513356367747, + "csv_write_time_avg": 0.0 + } + }, + { + "timestamp": "2025-08-16T18:23:08.720628", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 36 points saved, 0 lost, 0.0% CPU", + "details": { + "duration": 10.032164812088013, + "points_saved": 36, + "points_rate": 3.5884577929404307, + "variables_saved": 72, + "udp_points_sent": 0, + "points_lost": 0, + "cpu_average": 0.0, + "cpu_max": 0.0, + "delay_average": 0.0, + "delay_max": 0.0, + "read_errors": 0, + "csv_errors": 0, + "udp_errors": 0, + "read_time_avg": 0.10894164111879137, + "csv_write_time_avg": 3.7749608357747397e-06 + } + }, + { + "timestamp": "2025-08-16T18:23:18.759764", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 35 points saved, 0 lost, 0.2% CPU", + "details": { + "duration": 10.039902210235596, + "points_saved": 35, + "points_rate": 3.4860897314634993, + "variables_saved": 70, + "udp_points_sent": 0, + "points_lost": 0, + "cpu_average": 0.2, + "cpu_max": 0.2, + "delay_average": 0.0, + "delay_max": 0.0, + "read_errors": 0, + "csv_errors": 0, + "udp_errors": 0, + "read_time_avg": 0.10567408970424107, + "csv_write_time_avg": 6.278582981654576e-05 + } + }, + { + "timestamp": "2025-08-16T18:23:28.787986", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 37 points saved, 0 lost, 0.2% CPU", + "details": { + "duration": 10.028222560882568, + "points_saved": 37, + "points_rate": 3.6895870405117623, + "variables_saved": 74, + "udp_points_sent": 0, + "points_lost": 0, + "cpu_average": 0.2, + "cpu_max": 0.2, + "delay_average": 0.0, + "delay_max": 0.0, + "read_errors": 0, + "csv_errors": 0, + "udp_errors": 0, + "read_time_avg": 0.10496509397352063, + "csv_write_time_avg": 1.5207239099451013e-06 + } + }, + { + "timestamp": "2025-08-16T18:23:32.205391", + "level": "info", + "event_type": "udp_streaming_stopped", + "message": "UDP streaming to PlotJuggler stopped (CSV recording continues)", + "details": {} + }, + { + "timestamp": "2025-08-16T18:23:34.234104", + "level": "info", + "event_type": "csv_recording_stopped", + "message": "🔥 CRITICAL: CSV recording stopped (dataset threads continue for UDP streaming)", + "details": { + "recording_protection": false, + "performance_monitoring": false + } + }, + { + "timestamp": "2025-08-16T18:23:34.251601", + "level": "info", + "event_type": "udp_streaming_stopped", + "message": "UDP streaming to PlotJuggler stopped (CSV recording continues)", + "details": {} + }, + { + "timestamp": "2025-08-16T18:23:34.339727", + "level": "info", + "event_type": "dataset_deactivated", + "message": "Dataset deactivated: Fast", + "details": { + "dataset_id": "Fast" + } + }, + { + "timestamp": "2025-08-16T18:23:34.372354", + "level": "info", + "event_type": "dataset_deactivated", + "message": "Dataset deactivated: test", + "details": { + "dataset_id": "Test" + } + }, + { + "timestamp": "2025-08-16T18:23:34.620272", + "level": "info", + "event_type": "dataset_deactivated", + "message": "Dataset deactivated: DAR", + "details": { + "dataset_id": "DAR" + } + }, + { + "timestamp": "2025-08-16T18:23:34.638294", + "level": "info", + "event_type": "plc_disconnection", + "message": "Disconnected from PLC 10.1.33.11 (application shutdown (will auto-reconnect on restart))", + "details": {} + }, + { + "timestamp": "2025-08-16T18:23:41.492942", + "level": "info", + "event_type": "application_started", + "message": "Application initialization completed successfully", + "details": {} + }, + { + "timestamp": "2025-08-16T18:23:41.576182", + "level": "info", + "event_type": "dataset_activated", + "message": "Dataset activated: DAR", + "details": { + "dataset_id": "DAR", + "variables_count": 2, + "streaming_count": 2, + "prefix": "gateway_phoenix" + } + }, + { + "timestamp": "2025-08-16T18:23:41.594185", + "level": "info", + "event_type": "dataset_activated", + "message": "Dataset activated: Fast", + "details": { + "dataset_id": "Fast", + "variables_count": 2, + "streaming_count": 2, + "prefix": "fast" + } + }, + { + "timestamp": "2025-08-16T18:23:41.612184", + "level": "info", + "event_type": "csv_recording_started", + "message": "🔥 CRITICAL PRIORITY: CSV recording started with MAXIMUM PRIORITY and performance monitoring: 2 datasets activated", + "details": { + "activated_datasets": 2, + "total_datasets": 3, + "priority": "CRITICAL", + "recording_protection": true, + "performance_monitoring": true + } + }, + { + "timestamp": "2025-08-16T18:23:51.576314", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 36 points saved, 0 lost, 0.0% CPU", + "details": { + "duration": 11.088732242584229, + "points_saved": 36, + "points_rate": 3.2465388479441004, + "variables_saved": 72, + "udp_points_sent": 0, + "points_lost": 0, + "cpu_average": 0.0, + "cpu_max": 0.0, + "delay_average": 0.0, + "delay_max": 0.0, + "read_errors": 0, + "csv_errors": 0, + "udp_errors": 0, + "read_time_avg": 0.04650178220536974, + "csv_write_time_avg": 0.0003892713122897678 + } + }, + { + "timestamp": "2025-08-16T18:24:01.594658", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 37 points saved, 0 lost, 0.2% CPU", + "details": { + "duration": 10.018344640731812, + "points_saved": 37, + "points_rate": 3.693224911585519, + "variables_saved": 74, + "udp_points_sent": 0, + "points_lost": 0, + "cpu_average": 0.2, + "cpu_max": 0.2, + "delay_average": 0.0, + "delay_max": 0.0, + "read_errors": 0, + "csv_errors": 0, + "udp_errors": 0, + "read_time_avg": 0.044695138931274414, + "csv_write_time_avg": 2.9254604030299833e-05 + } + }, + { + "timestamp": "2025-08-16T18:24:11.614425", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 36 points saved, 0 lost, 0.2% CPU", + "details": { + "duration": 10.019767045974731, + "points_saved": 36, + "points_rate": 3.5928979021984726, + "variables_saved": 72, + "udp_points_sent": 0, + "points_lost": 0, + "cpu_average": 0.2, + "cpu_max": 0.2, + "delay_average": 0.0, + "delay_max": 0.0, + "read_errors": 0, + "csv_errors": 0, + "udp_errors": 0, + "read_time_avg": 0.04488941695955065, + "csv_write_time_avg": 0.0 + } + }, + { + "timestamp": "2025-08-16T18:24:21.630648", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 36 points saved, 0 lost, 0.0% CPU", + "details": { + "duration": 10.016222715377808, + "points_saved": 36, + "points_rate": 3.594169281472701, + "variables_saved": 72, + "udp_points_sent": 0, + "points_lost": 0, + "cpu_average": 0.0, + "cpu_max": 0.0, + "delay_average": 0.0, + "delay_max": 0.0, + "read_errors": 0, + "csv_errors": 0, + "udp_errors": 0, + "read_time_avg": 0.0362715654902988, + "csv_write_time_avg": 0.0 + } + }, + { + "timestamp": "2025-08-16T18:24:31.647847", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 36 points saved, 0 lost, 0.0% CPU", + "details": { + "duration": 10.01719856262207, + "points_saved": 36, + "points_rate": 3.5938191476337025, + "variables_saved": 72, + "udp_points_sent": 0, + "points_lost": 0, + "cpu_average": 0.0, + "cpu_max": 0.0, + "delay_average": 0.0, + "delay_max": 0.0, + "read_errors": 0, + "csv_errors": 0, + "udp_errors": 0, + "read_time_avg": 0.03559539715449015, + "csv_write_time_avg": 0.0 + } + }, + { + "timestamp": "2025-08-16T18:24:41.664429", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 36 points saved, 0 lost, 0.0% CPU", + "details": { + "duration": 10.016581773757935, + "points_saved": 36, + "points_rate": 3.594040443448986, + "variables_saved": 72, + "udp_points_sent": 0, + "points_lost": 0, + "cpu_average": 0.0, + "cpu_max": 0.0, + "delay_average": 0.0, + "delay_max": 0.0, + "read_errors": 0, + "csv_errors": 0, + "udp_errors": 0, + "read_time_avg": 0.033702042367723256, + "csv_write_time_avg": 0.0 + } + }, + { + "timestamp": "2025-08-16T18:24:51.681860", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 36 points saved, 0 lost, 0.0% CPU", + "details": { + "duration": 10.017431497573853, + "points_saved": 36, + "points_rate": 3.5937355806944056, + "variables_saved": 72, + "udp_points_sent": 0, + "points_lost": 0, + "cpu_average": 0.0, + "cpu_max": 0.0, + "delay_average": 0.0, + "delay_max": 0.0, + "read_errors": 0, + "csv_errors": 0, + "udp_errors": 0, + "read_time_avg": 0.03262894683414035, + "csv_write_time_avg": 0.0 + } + }, + { + "timestamp": "2025-08-16T18:25:01.699151", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 36 points saved, 0 lost, 0.0% CPU", + "details": { + "duration": 10.01729130744934, + "points_saved": 36, + "points_rate": 3.593785874353945, + "variables_saved": 72, + "udp_points_sent": 0, + "points_lost": 0, + "cpu_average": 0.0, + "cpu_max": 0.0, + "delay_average": 0.0, + "delay_max": 0.0, + "read_errors": 0, + "csv_errors": 0, + "udp_errors": 0, + "read_time_avg": 0.04057797458436754, + "csv_write_time_avg": 0.0 + } + }, + { + "timestamp": "2025-08-16T18:25:11.716164", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 37 points saved, 0 lost, 0.0% CPU", + "details": { + "duration": 10.01701283454895, + "points_saved": 37, + "points_rate": 3.693715942180486, + "variables_saved": 74, + "udp_points_sent": 0, + "points_lost": 0, + "cpu_average": 0.0, + "cpu_max": 0.0, + "delay_average": 0.0, + "delay_max": 0.0, + "read_errors": 0, + "csv_errors": 0, + "udp_errors": 0, + "read_time_avg": 0.03774530178791768, + "csv_write_time_avg": 1.7526987436655406e-06 + } + }, + { + "timestamp": "2025-08-16T18:25:21.733241", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 36 points saved, 0 lost, 0.0% CPU", + "details": { + "duration": 10.01707649230957, + "points_saved": 36, + "points_rate": 3.5938629427097166, + "variables_saved": 72, + "udp_points_sent": 0, + "points_lost": 0, + "cpu_average": 0.0, + "cpu_max": 0.0, + "delay_average": 0.0, + "delay_max": 0.0, + "read_errors": 0, + "csv_errors": 0, + "udp_errors": 0, + "read_time_avg": 0.0388162997033861, + "csv_write_time_avg": 0.0 + } + }, + { + "timestamp": "2025-08-16T18:25:31.750935", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 36 points saved, 0 lost, 0.2% CPU", + "details": { + "duration": 10.01769471168518, + "points_saved": 36, + "points_rate": 3.593641155585192, + "variables_saved": 72, + "udp_points_sent": 0, + "points_lost": 0, + "cpu_average": 0.2, + "cpu_max": 0.2, + "delay_average": 0.0, + "delay_max": 0.0, + "read_errors": 0, + "csv_errors": 0, + "udp_errors": 0, + "read_time_avg": 0.0382196307182312, + "csv_write_time_avg": 0.0 + } + }, + { + "timestamp": "2025-08-16T18:25:41.768076", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 36 points saved, 0 lost, 0.0% CPU", + "details": { + "duration": 10.017140865325928, + "points_saved": 36, + "points_rate": 3.5938398475170756, + "variables_saved": 72, + "udp_points_sent": 0, + "points_lost": 0, + "cpu_average": 0.0, + "cpu_max": 0.0, + "delay_average": 0.0, + "delay_max": 0.0, + "read_errors": 0, + "csv_errors": 0, + "udp_errors": 0, + "read_time_avg": 0.03385060363345676, + "csv_write_time_avg": 0.0 + } + }, + { + "timestamp": "2025-08-16T18:25:51.784697", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 36 points saved, 0 lost, 0.2% CPU", + "details": { + "duration": 10.016620635986328, + "points_saved": 36, + "points_rate": 3.594026499382854, + "variables_saved": 72, + "udp_points_sent": 0, + "points_lost": 0, + "cpu_average": 0.2, + "cpu_max": 0.2, + "delay_average": 0.0, + "delay_max": 0.0, + "read_errors": 0, + "csv_errors": 0, + "udp_errors": 0, + "read_time_avg": 0.03625632656945123, + "csv_write_time_avg": 0.0 + } + }, + { + "timestamp": "2025-08-16T18:26:01.802073", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 36 points saved, 0 lost, 0.0% CPU", + "details": { + "duration": 10.01737642288208, + "points_saved": 36, + "points_rate": 3.593755338749915, + "variables_saved": 72, + "udp_points_sent": 0, + "points_lost": 0, + "cpu_average": 0.0, + "cpu_max": 0.0, + "delay_average": 0.0, + "delay_max": 0.0, + "read_errors": 0, + "csv_errors": 0, + "udp_errors": 0, + "read_time_avg": 0.039837261041005455, + "csv_write_time_avg": 0.0 + } + }, + { + "timestamp": "2025-08-16T18:26:11.818652", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 36 points saved, 0 lost, 0.0% CPU", + "details": { + "duration": 10.016578435897827, + "points_saved": 36, + "points_rate": 3.5940416411038836, + "variables_saved": 72, + "udp_points_sent": 0, + "points_lost": 0, + "cpu_average": 0.0, + "cpu_max": 0.0, + "delay_average": 0.0, + "delay_max": 0.0, + "read_errors": 0, + "csv_errors": 0, + "udp_errors": 0, + "read_time_avg": 0.0869104266166687, + "csv_write_time_avg": 0.0 + } + }, + { + "timestamp": "2025-08-16T18:26:21.927237", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 34 points saved, 0 lost, 0.6% CPU", + "details": { + "duration": 10.06232213973999, + "points_saved": 34, + "points_rate": 3.378941712243627, + "variables_saved": 68, + "udp_points_sent": 0, + "points_lost": 0, + "cpu_average": 0.6, + "cpu_max": 0.6, + "delay_average": 0.0, + "delay_max": 0.0, + "read_errors": 0, + "csv_errors": 0, + "udp_errors": 0, + "read_time_avg": 0.18056527306051814, + "csv_write_time_avg": 0.011022399453555836 + } + }, + { + "timestamp": "2025-08-16T18:26:32.828534", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 38 points saved, 0 lost, 33.1% CPU", + "details": { + "duration": 10.90151834487915, + "points_saved": 38, + "points_rate": 3.4857529747542015, + "variables_saved": 76, + "udp_points_sent": 0, + "points_lost": 0, + "cpu_average": 33.1, + "cpu_max": 33.1, + "delay_average": 0.0, + "delay_max": 0.0, + "read_errors": 0, + "csv_errors": 0, + "udp_errors": 0, + "read_time_avg": 0.19401655699077405, + "csv_write_time_avg": 0.01511844835783306 + } + }, + { + "timestamp": "2025-08-16T18:26:43.680506", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 39 points saved, 0 lost, 33.1% CPU", + "details": { + "duration": 10.898014307022095, + "points_saved": 39, + "points_rate": 3.5786335841815236, + "variables_saved": 78, + "udp_points_sent": 0, + "points_lost": 0, + "cpu_average": 33.1, + "cpu_max": 33.1, + "delay_average": 0.0, + "delay_max": 0.0, + "read_errors": 0, + "csv_errors": 0, + "udp_errors": 0, + "read_time_avg": 0.14690295243874574, + "csv_write_time_avg": 0.003972077981019631 + } + }, + { + "timestamp": "2025-08-16T18:26:53.718088", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 36 points saved, 0 lost, 9.6% CPU", + "details": { + "duration": 10.037581205368042, + "points_saved": 36, + "points_rate": 3.586521420195077, + "variables_saved": 72, + "udp_points_sent": 0, + "points_lost": 0, + "cpu_average": 9.6, + "cpu_max": 9.6, + "delay_average": 0.0, + "delay_max": 0.0, + "read_errors": 0, + "csv_errors": 0, + "udp_errors": 0, + "read_time_avg": 0.10698958900239733, + "csv_write_time_avg": 5.351172553168402e-06 + } + }, + { + "timestamp": "2025-08-16T18:27:03.766412", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 35 points saved, 0 lost, 0.3% CPU", + "details": { + "duration": 10.048324584960938, + "points_saved": 35, + "points_rate": 3.4831677364785345, + "variables_saved": 70, + "udp_points_sent": 0, + "points_lost": 0, + "cpu_average": 0.3, + "cpu_max": 0.3, + "delay_average": 0.0, + "delay_max": 0.0, + "read_errors": 0, + "csv_errors": 0, + "udp_errors": 0, + "read_time_avg": 0.10907115255083356, + "csv_write_time_avg": 7.459095546177455e-06 + } + }, + { + "timestamp": "2025-08-16T18:27:13.799743", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 36 points saved, 0 lost, 0.3% CPU", + "details": { + "duration": 10.033330202102661, + "points_saved": 36, + "points_rate": 3.588040986875481, + "variables_saved": 72, + "udp_points_sent": 0, + "points_lost": 0, + "cpu_average": 0.3, + "cpu_max": 0.3, + "delay_average": 0.0, + "delay_max": 0.0, + "read_errors": 0, + "csv_errors": 0, + "udp_errors": 0, + "read_time_avg": 0.11147182517581516, + "csv_write_time_avg": 1.020563973320855e-05 + } + }, + { + "timestamp": "2025-08-16T18:27:23.898255", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 35 points saved, 0 lost, 0.3% CPU", + "details": { + "duration": 10.067713260650635, + "points_saved": 35, + "points_rate": 3.4764597574303675, + "variables_saved": 70, + "udp_points_sent": 0, + "points_lost": 0, + "cpu_average": 0.3, + "cpu_max": 0.3, + "delay_average": 0.0, + "delay_max": 0.0, + "read_errors": 0, + "csv_errors": 0, + "udp_errors": 0, + "read_time_avg": 0.17638461249215262, + "csv_write_time_avg": 0.011402770451136997 + } + }, + { + "timestamp": "2025-08-16T18:27:34.835158", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 39 points saved, 0 lost, 26.0% CPU", + "details": { + "duration": 10.967023134231567, + "points_saved": 39, + "points_rate": 3.5561154127840395, + "variables_saved": 78, + "udp_points_sent": 0, + "points_lost": 0, + "cpu_average": 26.0, + "cpu_max": 26.0, + "delay_average": 0.0, + "delay_max": 0.0, + "read_errors": 0, + "csv_errors": 0, + "udp_errors": 0, + "read_time_avg": 0.1639550037873097, + "csv_write_time_avg": 0.011529690180069361 + } + }, + { + "timestamp": "2025-08-16T18:27:44.887333", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 35 points saved, 0 lost, 20.8% CPU", + "details": { + "duration": 10.05285382270813, + "points_saved": 35, + "points_rate": 3.481598421429287, + "variables_saved": 70, + "udp_points_sent": 0, + "points_lost": 0, + "cpu_average": 20.8, + "cpu_max": 20.8, + "delay_average": 0.0, + "delay_max": 0.0, + "read_errors": 0, + "csv_errors": 0, + "udp_errors": 0, + "read_time_avg": 0.10730040413992746, + "csv_write_time_avg": 6.621224539620536e-06 + } + }, + { + "timestamp": "2025-08-16T18:27:54.932299", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 36 points saved, 0 lost, 0.3% CPU", + "details": { + "duration": 10.044966459274292, + "points_saved": 36, + "points_rate": 3.583884540178032, + "variables_saved": 72, + "udp_points_sent": 0, + "points_lost": 0, + "cpu_average": 0.3, + "cpu_max": 0.3, + "delay_average": 0.0, + "delay_max": 0.0, + "read_errors": 0, + "csv_errors": 0, + "udp_errors": 0, + "read_time_avg": 0.10931764708624946, + "csv_write_time_avg": 2.3769007788764106e-05 + } + }, + { + "timestamp": "2025-08-16T18:28:04.973331", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 36 points saved, 0 lost, 0.3% CPU", + "details": { + "duration": 10.041032075881958, + "points_saved": 36, + "points_rate": 3.5852888157254417, + "variables_saved": 72, + "udp_points_sent": 0, + "points_lost": 0, + "cpu_average": 0.3, + "cpu_max": 0.3, + "delay_average": 0.0, + "delay_max": 0.0, + "read_errors": 0, + "csv_errors": 0, + "udp_errors": 0, + "read_time_avg": 0.10538231664233738, + "csv_write_time_avg": 3.6491288079155816e-06 + } + }, + { + "timestamp": "2025-08-16T18:28:14.996801", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 35 points saved, 0 lost, 0.2% CPU", + "details": { + "duration": 10.023469686508179, + "points_saved": 35, + "points_rate": 3.4918048434975373, + "variables_saved": 70, + "udp_points_sent": 0, + "points_lost": 0, + "cpu_average": 0.2, + "cpu_max": 0.2, + "delay_average": 0.0, + "delay_max": 0.0, + "read_errors": 0, + "csv_errors": 0, + "udp_errors": 0, + "read_time_avg": 0.10980193274361746, + "csv_write_time_avg": 1.4087132045200894e-05 + } + }, + { + "timestamp": "2025-08-16T18:28:22.596080", + "level": "info", + "event_type": "config_reload", + "message": "Dataset configuration reloaded from files with CSV header validation", + "details": { + "datasets_count": 3, + "active_datasets_count": 3, + "csv_recording_active": true + } + }, + { + "timestamp": "2025-08-16T18:28:25.026671", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 36 points saved, 0 lost, 0.3% CPU", + "details": { + "duration": 10.02987003326416, + "points_saved": 36, + "points_rate": 3.5892788122483794, + "variables_saved": 72, + "udp_points_sent": 0, + "points_lost": 0, + "cpu_average": 0.3, + "cpu_max": 0.3, + "delay_average": 0.0, + "delay_max": 0.0, + "read_errors": 0, + "csv_errors": 0, + "udp_errors": 0, + "read_time_avg": 0.10965166489283244, + "csv_write_time_avg": 4.861752192179362e-05 + } + }, + { + "timestamp": "2025-08-16T18:28:35.067107", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 36 points saved, 0 lost, 0.6% CPU", + "details": { + "duration": 10.03954553604126, + "points_saved": 36, + "points_rate": 3.5858196838455028, + "variables_saved": 72, + "udp_points_sent": 0, + "points_lost": 0, + "cpu_average": 0.6, + "cpu_max": 0.6, + "delay_average": 0.0, + "delay_max": 0.0, + "read_errors": 0, + "csv_errors": 0, + "udp_errors": 0, + "read_time_avg": 0.08615738153457642, + "csv_write_time_avg": 0.0 + } + }, + { + "timestamp": "2025-08-16T18:28:45.083203", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 36 points saved, 0 lost, 0.0% CPU", + "details": { + "duration": 10.016986846923828, + "points_saved": 36, + "points_rate": 3.5938951053984303, + "variables_saved": 72, + "udp_points_sent": 0, + "points_lost": 0, + "cpu_average": 0.0, + "cpu_max": 0.0, + "delay_average": 0.0, + "delay_max": 0.0, + "read_errors": 0, + "csv_errors": 0, + "udp_errors": 0, + "read_time_avg": 0.037027094099256724, + "csv_write_time_avg": 0.0 + } + }, + { + "timestamp": "2025-08-16T18:28:55.099939", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 36 points saved, 0 lost, 0.0% CPU", + "details": { + "duration": 10.016735553741455, + "points_saved": 36, + "points_rate": 3.593985266642411, + "variables_saved": 72, + "udp_points_sent": 0, + "points_lost": 0, + "cpu_average": 0.0, + "cpu_max": 0.0, + "delay_average": 0.0, + "delay_max": 0.0, + "read_errors": 0, + "csv_errors": 0, + "udp_errors": 0, + "read_time_avg": 0.04507075415717231, + "csv_write_time_avg": 0.0 + } + }, + { + "timestamp": "2025-08-16T18:29:05.116074", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 36 points saved, 0 lost, 0.2% CPU", + "details": { + "duration": 10.016135454177856, + "points_saved": 36, + "points_rate": 3.594200594100786, + "variables_saved": 72, + "udp_points_sent": 0, + "points_lost": 0, + "cpu_average": 0.2, + "cpu_max": 0.2, + "delay_average": 0.0, + "delay_max": 0.0, + "read_errors": 0, + "csv_errors": 0, + "udp_errors": 0, + "read_time_avg": 0.037626167138417564, + "csv_write_time_avg": 0.0 + } + }, + { + "timestamp": "2025-08-16T18:29:15.134319", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 36 points saved, 0 lost, 0.2% CPU", + "details": { + "duration": 10.018244981765747, + "points_saved": 36, + "points_rate": 3.593443768396936, + "variables_saved": 72, + "udp_points_sent": 0, + "points_lost": 0, + "cpu_average": 0.2, + "cpu_max": 0.2, + "delay_average": 0.0, + "delay_max": 0.0, + "read_errors": 0, + "csv_errors": 0, + "udp_errors": 0, + "read_time_avg": 0.03699025180604723, + "csv_write_time_avg": 0.0 + } + }, + { + "timestamp": "2025-08-16T18:29:22.380379", + "level": "info", + "event_type": "csv_recording_stopped", + "message": "🔥 CRITICAL: CSV recording stopped (dataset threads continue for UDP streaming)", + "details": { + "recording_protection": false, + "performance_monitoring": false + } + }, + { + "timestamp": "2025-08-16T18:29:22.396260", + "level": "info", + "event_type": "udp_streaming_stopped", + "message": "UDP streaming to PlotJuggler stopped (CSV recording continues)", + "details": {} + }, + { + "timestamp": "2025-08-16T18:29:22.906030", + "level": "info", + "event_type": "dataset_deactivated", + "message": "Dataset deactivated: DAR", + "details": { + "dataset_id": "DAR" + } + }, + { + "timestamp": "2025-08-16T18:29:22.922598", + "level": "info", + "event_type": "dataset_deactivated", + "message": "Dataset deactivated: test", + "details": { + "dataset_id": "Test" + } + }, + { + "timestamp": "2025-08-16T18:29:23.152861", + "level": "info", + "event_type": "dataset_deactivated", + "message": "Dataset deactivated: Fast", + "details": { + "dataset_id": "Fast" + } + }, + { + "timestamp": "2025-08-16T18:29:23.169976", + "level": "info", + "event_type": "plc_disconnection", + "message": "Disconnected from PLC 10.1.33.11 (manually disconnected)", + "details": {} + }, + { + "timestamp": "2025-08-16T18:31:59.337677", + "level": "info", + "event_type": "udp_streaming_stopped", + "message": "UDP streaming to PlotJuggler stopped (CSV recording continues)", + "details": {} + }, + { + "timestamp": "2025-08-16T18:31:59.354198", + "level": "info", + "event_type": "csv_recording_stopped", + "message": "🔥 CRITICAL: CSV recording stopped (dataset threads continue for UDP streaming)", + "details": { + "recording_protection": false, + "performance_monitoring": false + } + }, + { + "timestamp": "2025-08-16T18:31:59.372382", + "level": "info", + "event_type": "udp_streaming_stopped", + "message": "UDP streaming to PlotJuggler stopped (CSV recording continues)", + "details": {} + }, + { + "timestamp": "2025-08-16T18:31:59.388374", + "level": "info", + "event_type": "plc_disconnection", + "message": "Disconnected from PLC 10.1.33.11 (application shutdown (will auto-reconnect on restart))", + "details": {} + }, + { + "timestamp": "2025-08-16T18:32:06.856060", + "level": "info", + "event_type": "application_started", + "message": "Application initialization completed successfully", + "details": {} + }, + { + "timestamp": "2025-08-16T18:32:30.238313", + "level": "info", + "event_type": "dataset_activated", + "message": "Dataset activated: DAR", + "details": { + "dataset_id": "DAR", + "variables_count": 2, + "streaming_count": 2, + "prefix": "gateway_phoenix" + } + }, + { + "timestamp": "2025-08-16T18:32:30.269189", + "level": "info", + "event_type": "dataset_activated", + "message": "Dataset activated: Fast", + "details": { + "dataset_id": "Fast", + "variables_count": 2, + "streaming_count": 2, + "prefix": "fast" + } + }, + { + "timestamp": "2025-08-16T18:32:30.302524", + "level": "info", + "event_type": "csv_recording_started", + "message": "🔥 CRITICAL PRIORITY: CSV recording started with MAXIMUM PRIORITY and performance monitoring: 2 datasets activated", + "details": { + "activated_datasets": 2, + "total_datasets": 3, + "priority": "CRITICAL", + "recording_protection": true, + "performance_monitoring": true + } + }, + { + "timestamp": "2025-08-16T18:32:30.339062", + "level": "info", + "event_type": "plc_connection", + "message": "Successfully connected to PLC 10.1.33.11 and auto-started CSV recording for 3 datasets", + "details": { + "ip": "10.1.33.11", + "rack": 0, + "slot": 2, + "symbols_path": "C:/Users/migue/Downloads/symSAE452.asc", + "auto_started_recording": true, + "recording_datasets": 3, + "dataset_names": [ + "DAR", + "test", + "Fast" + ] + } + }, + { + "timestamp": "2025-08-16T18:32:40.238147", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 30 points saved, 0 lost, 0.0% CPU", + "details": { + "duration": 34.394169330596924, + "points_saved": 30, + "points_rate": 0.872240864770998, + "variables_saved": 60, + "udp_points_sent": 0, + "points_lost": 0, + "cpu_average": 0.0, + "cpu_max": 0.0, + "delay_average": 0.0, + "delay_max": 0.0, + "read_errors": 0, + "csv_errors": 0, + "udp_errors": 0, + "read_time_avg": 0.08476141293843588, + "csv_write_time_avg": 0.0003764793790619949 + } + }, + { + "timestamp": "2025-08-16T18:32:43.053315", + "level": "info", + "event_type": "plot_session_created", + "message": "Plot session 'UR29' created and started", + "details": { + "session_id": "plot_1_1755361963053_2", + "variables": [ + "UR29_Brix", + "UR29_ma", + "AUX Blink_1.0S", + "AUX Blink_1.6S" + ], + "time_window": 36, + "trigger_variable": null, + "auto_started": true + } + }, + { + "timestamp": "2025-08-16T18:32:50.281813", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 30 points saved, 0 lost, 0.9% CPU", + "details": { + "duration": 10.043666124343872, + "points_saved": 30, + "points_rate": 2.986957115916657, + "variables_saved": 60, + "udp_points_sent": 0, + "points_lost": 0, + "cpu_average": 0.9, + "cpu_max": 0.9, + "delay_average": 0.0, + "delay_max": 0.0, + "read_errors": 0, + "csv_errors": 0, + "udp_errors": 0, + "read_time_avg": 0.10776501496632894, + "csv_write_time_avg": 5.62588373819987e-05 + } + }, + { + "timestamp": "2025-08-16T18:33:00.331566", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 29 points saved, 0 lost, 0.5% CPU", + "details": { + "duration": 10.049752235412598, + "points_saved": 29, + "points_rate": 2.885643279623539, + "variables_saved": 58, + "udp_points_sent": 0, + "points_lost": 0, + "cpu_average": 0.5, + "cpu_max": 0.5, + "delay_average": 0.0, + "delay_max": 0.0, + "read_errors": 0, + "csv_errors": 0, + "udp_errors": 0, + "read_time_avg": 0.1179089381777007, + "csv_write_time_avg": 0.001501214915308459 + } + }, + { + "timestamp": "2025-08-16T18:33:10.363911", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 30 points saved, 0 lost, 15.2% CPU", + "details": { + "duration": 10.032345533370972, + "points_saved": 30, + "points_rate": 2.990327625798958, + "variables_saved": 60, + "udp_points_sent": 0, + "points_lost": 0, + "cpu_average": 15.2, + "cpu_max": 15.2, + "delay_average": 0.0, + "delay_max": 0.0, + "read_errors": 0, + "csv_errors": 0, + "udp_errors": 0, + "read_time_avg": 0.11747097174326579, + "csv_write_time_avg": 0.0005184332529703776 + } + }, + { + "timestamp": "2025-08-16T18:33:20.398475", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 29 points saved, 0 lost, 7.5% CPU", + "details": { + "duration": 10.034563302993774, + "points_saved": 29, + "points_rate": 2.8900111668385167, + "variables_saved": 58, + "udp_points_sent": 0, + "points_lost": 0, + "cpu_average": 7.5, + "cpu_max": 7.5, + "delay_average": 0.0, + "delay_max": 0.0, + "read_errors": 0, + "csv_errors": 0, + "udp_errors": 0, + "read_time_avg": 0.14085213891391096, + "csv_write_time_avg": 0.0021928918772730335 + } + }, + { + "timestamp": "2025-08-16T18:33:30.434769", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 30 points saved, 0 lost, 10.1% CPU", + "details": { + "duration": 10.036294221878052, + "points_saved": 30, + "points_rate": 2.9891511086435867, + "variables_saved": 60, + "udp_points_sent": 0, + "points_lost": 0, + "cpu_average": 10.1, + "cpu_max": 10.1, + "delay_average": 0.0, + "delay_max": 0.0, + "read_errors": 0, + "csv_errors": 0, + "udp_errors": 0, + "read_time_avg": 0.11473293304443359, + "csv_write_time_avg": 0.0026844898859659833 + } + }, + { + "timestamp": "2025-08-16T18:33:40.481282", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 30 points saved, 0 lost, 11.5% CPU", + "details": { + "duration": 10.045766592025757, + "points_saved": 30, + "points_rate": 2.986332573545332, + "variables_saved": 60, + "udp_points_sent": 0, + "points_lost": 0, + "cpu_average": 11.5, + "cpu_max": 11.5, + "delay_average": 0.0, + "delay_max": 0.0, + "read_errors": 0, + "csv_errors": 0, + "udp_errors": 0, + "read_time_avg": 0.1166374127070109, + "csv_write_time_avg": 0.0025274038314819338 + } + }, + { + "timestamp": "2025-08-16T18:33:50.514989", + "level": "info", + "event_type": "csv_recording_stopped", + "message": "🔥 CRITICAL: CSV recording stopped (dataset threads continue for UDP streaming)", + "details": { + "recording_protection": false, + "performance_monitoring": false + } + }, + { + "timestamp": "2025-08-16T18:33:50.549123", + "level": "info", + "event_type": "udp_streaming_stopped", + "message": "UDP streaming to PlotJuggler stopped (CSV recording continues)", + "details": {} + }, + { + "timestamp": "2025-08-16T18:33:50.625004", + "level": "info", + "event_type": "dataset_deactivated", + "message": "Dataset deactivated: DAR", + "details": { + "dataset_id": "DAR" + } + }, + { + "timestamp": "2025-08-16T18:33:50.659332", + "level": "info", + "event_type": "dataset_deactivated", + "message": "Dataset deactivated: test", + "details": { + "dataset_id": "Test" + } + }, + { + "timestamp": "2025-08-16T18:33:51.076861", + "level": "info", + "event_type": "dataset_deactivated", + "message": "Dataset deactivated: Fast", + "details": { + "dataset_id": "Fast" + } + }, + { + "timestamp": "2025-08-16T18:33:51.101903", + "level": "info", + "event_type": "plc_disconnection", + "message": "Disconnected from PLC 10.1.33.11 (manually disconnected)", + "details": {} + }, + { + "timestamp": "2025-08-16T18:34:02.872414", + "level": "info", + "event_type": "dataset_activated", + "message": "Dataset activated: DAR", + "details": { + "dataset_id": "DAR", + "variables_count": 2, + "streaming_count": 2, + "prefix": "gateway_phoenix" + } + }, + { + "timestamp": "2025-08-16T18:34:02.900196", + "level": "info", + "event_type": "dataset_activated", + "message": "Dataset activated: Fast", + "details": { + "dataset_id": "Fast", + "variables_count": 2, + "streaming_count": 2, + "prefix": "fast" + } + }, + { + "timestamp": "2025-08-16T18:34:02.936037", + "level": "info", + "event_type": "csv_recording_started", + "message": "🔥 CRITICAL PRIORITY: CSV recording started with MAXIMUM PRIORITY and performance monitoring: 2 datasets activated", + "details": { + "activated_datasets": 2, + "total_datasets": 3, + "priority": "CRITICAL", + "recording_protection": true, + "performance_monitoring": true + } + }, + { + "timestamp": "2025-08-16T18:34:02.974553", + "level": "info", + "event_type": "plc_connection", + "message": "Successfully connected to PLC 10.1.33.11 and auto-started CSV recording for 2 datasets", + "details": { + "ip": "10.1.33.11", + "rack": 0, + "slot": 2, + "symbols_path": "C:/Users/migue/Downloads/symSAE452.asc", + "auto_started_recording": true, + "recording_datasets": 2, + "dataset_names": [ + "DAR", + "Fast" + ] + } + }, + { + "timestamp": "2025-08-16T18:34:12.887931", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 59 points saved, 35 lost, 6.2% CPU", + "details": { + "duration": 32.406327962875366, + "points_saved": 59, + "points_rate": 1.8206320712297395, + "variables_saved": 118, + "udp_points_sent": 0, + "points_lost": 35, + "cpu_average": 6.2, + "cpu_max": 11.5, + "delay_average": 0.0, + "delay_max": 0.0, + "read_errors": 0, + "csv_errors": 0, + "udp_errors": 0, + "read_time_avg": 0.1186170416363215, + "csv_write_time_avg": 0.0008189545737372504 + } + }, + { + "timestamp": "2025-08-16T18:34:22.923863", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 29 points saved, 0 lost, 0.3% CPU", + "details": { + "duration": 10.036999702453613, + "points_saved": 29, + "points_rate": 2.8893096403012497, + "variables_saved": 58, + "udp_points_sent": 0, + "points_lost": 0, + "cpu_average": 0.3, + "cpu_max": 0.3, + "delay_average": 0.0, + "delay_max": 0.0, + "read_errors": 0, + "csv_errors": 0, + "udp_errors": 0, + "read_time_avg": 0.10199150545843716, + "csv_write_time_avg": 1.904060100686961e-05 + } } ], - "last_updated": "2025-08-16T16:41:27.495418", - "total_entries": 740 + "last_updated": "2025-08-16T18:34:22.923863", + "total_entries": 1000 } \ No newline at end of file diff --git a/config/data/dataset_definitions.json b/config/data/dataset_definitions.json index 7dc0ba0..24404dc 100644 --- a/config/data/dataset_definitions.json +++ b/config/data/dataset_definitions.json @@ -14,7 +14,7 @@ "id": "Fast", "name": "Fast", "prefix": "fast", - "sampling_interval": 0.62 + "sampling_interval": 1 }, { "enabled": true, diff --git a/core/performance_monitor.py b/core/performance_monitor.py new file mode 100644 index 0000000..b4b8d9a --- /dev/null +++ b/core/performance_monitor.py @@ -0,0 +1,395 @@ +""" +Performance Monitor for PLC Data Streamer + +🔑 CORE PRINCIPLE: Real-time Performance Monitoring +================================================= +This module provides detailed monitoring of recording performance including: +- Points lost due to delays or read errors +- CPU usage statistics +- Recording and streaming throughput +- Error rates and timing analysis + +Logs every 10 seconds with comprehensive statistics. +""" + +import time +import threading +import psutil +from collections import deque, defaultdict +from datetime import datetime, timedelta +from typing import Dict, Any, Optional, List +from dataclasses import dataclass, field +import statistics + + +@dataclass +class PerformanceMetrics: + """Container for performance metrics over a time window""" + + # Timing metrics + read_delays: List[float] = field(default_factory=list) + read_times: List[float] = field(default_factory=list) + csv_write_times: List[float] = field(default_factory=list) + + # Throughput metrics + points_saved: int = 0 + variables_saved: int = 0 + udp_points_sent: int = 0 + + # Error metrics + read_errors: int = 0 + csv_errors: int = 0 + udp_errors: int = 0 + points_lost: int = 0 + + # CPU metrics + cpu_samples: List[float] = field(default_factory=list) + + # Timestamp tracking + start_time: float = field(default_factory=time.time) + + def reset(self): + """Reset all metrics for new measurement window""" + self.read_delays.clear() + self.read_times.clear() + self.csv_write_times.clear() + self.points_saved = 0 + self.variables_saved = 0 + self.udp_points_sent = 0 + self.read_errors = 0 + self.csv_errors = 0 + self.udp_errors = 0 + self.points_lost = 0 + self.cpu_samples.clear() + self.start_time = time.time() + + +class PerformanceMonitor: + """Real-time performance monitoring for PLC data streaming""" + + def __init__(self, logger=None, event_logger=None, report_interval=10.0): + self.logger = logger + self.event_logger = event_logger + self.report_interval = report_interval + + # Current metrics window + self.current_metrics = PerformanceMetrics() + + # Historical data (keep last 60 windows = 10 minutes) + self.historical_metrics = deque(maxlen=60) + + # Dataset-specific tracking + self.dataset_last_read = {} # dataset_id -> timestamp + self.dataset_expected_interval = {} # dataset_id -> interval + self.dataset_metrics = defaultdict(PerformanceMetrics) + + # Monitoring thread + self.monitoring_active = False + self.monitor_thread = None + self.lock = threading.Lock() + + # CPU monitoring + self.process = psutil.Process() + + def start_monitoring(self): + """Start performance monitoring thread""" + if self.monitoring_active: + return + + self.monitoring_active = True + self.monitor_thread = threading.Thread( + target=self._monitoring_loop, name="performance_monitor", daemon=True + ) + self.monitor_thread.start() + + if self.logger: + self.logger.info("🔍 Performance monitoring started (10s intervals)") + + def stop_monitoring(self): + """Stop performance monitoring thread""" + self.monitoring_active = False + if self.monitor_thread and self.monitor_thread.is_alive(): + self.monitor_thread.join(timeout=2.0) + + if self.logger: + self.logger.info("🔍 Performance monitoring stopped") + + def record_dataset_read( + self, + dataset_id: str, + read_time: float, + variables_count: int, + success: bool = True, + delay: float = 0.0, + ): + """Record a dataset read operation""" + with self.lock: + current_time = time.time() + + # Update dataset tracking + if dataset_id in self.dataset_last_read: + # Calculate actual interval vs expected + actual_interval = current_time - self.dataset_last_read[dataset_id] + expected_interval = self.dataset_expected_interval.get(dataset_id, 1.0) + + # Check for lost points due to delays + if actual_interval > expected_interval * 1.5: # 50% tolerance + lost_points = int( + (actual_interval - expected_interval) / expected_interval + ) + self.current_metrics.points_lost += lost_points + + if self.logger: + self.logger.warning( + f"⚠️ POINTS LOST: Dataset '{dataset_id}' - {lost_points} points lost " + f"(expected: {expected_interval:.2f}s, actual: {actual_interval:.2f}s, " + f"delay: {delay:.3f}s)" + ) + + self.dataset_last_read[dataset_id] = current_time + + # Record metrics + if success: + self.current_metrics.read_times.append(read_time) + self.current_metrics.points_saved += 1 + self.current_metrics.variables_saved += variables_count + + if delay > 0: + self.current_metrics.read_delays.append(delay) + else: + self.current_metrics.read_errors += 1 + + def record_csv_write( + self, dataset_id: str, write_time: float, success: bool = True + ): + """Record a CSV write operation""" + with self.lock: + if success: + self.current_metrics.csv_write_times.append(write_time) + else: + self.current_metrics.csv_errors += 1 + + def record_udp_send(self, variables_count: int, success: bool = True): + """Record a UDP send operation""" + with self.lock: + if success: + self.current_metrics.udp_points_sent += variables_count + else: + self.current_metrics.udp_errors += 1 + + def set_dataset_interval(self, dataset_id: str, interval: float): + """Set expected interval for a dataset""" + self.dataset_expected_interval[dataset_id] = interval + + def _monitoring_loop(self): + """Main monitoring loop that reports statistics every interval""" + while self.monitoring_active: + try: + # Sample CPU usage + with self.lock: + cpu_percent = self.process.cpu_percent() + self.current_metrics.cpu_samples.append(cpu_percent) + + # Wait for report interval + time.sleep(self.report_interval) + + if self.monitoring_active: + self._generate_report() + + except Exception as e: + if self.logger: + self.logger.error(f"Error in performance monitoring loop: {e}") + time.sleep(1.0) + + def _generate_report(self): + """Generate and log performance report""" + with self.lock: + # Create copy of current metrics + metrics = PerformanceMetrics( + read_delays=self.current_metrics.read_delays.copy(), + read_times=self.current_metrics.read_times.copy(), + csv_write_times=self.current_metrics.csv_write_times.copy(), + points_saved=self.current_metrics.points_saved, + variables_saved=self.current_metrics.variables_saved, + udp_points_sent=self.current_metrics.udp_points_sent, + read_errors=self.current_metrics.read_errors, + csv_errors=self.current_metrics.csv_errors, + udp_errors=self.current_metrics.udp_errors, + points_lost=self.current_metrics.points_lost, + cpu_samples=self.current_metrics.cpu_samples.copy(), + start_time=self.current_metrics.start_time, + ) + + # Store in history + self.historical_metrics.append(metrics) + + # Reset current metrics + self.current_metrics.reset() + + # Generate report + self._log_performance_report(metrics) + + def _log_performance_report(self, metrics: PerformanceMetrics): + """Log detailed performance report""" + duration = time.time() - metrics.start_time + timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S") + + # Calculate statistics + stats = self._calculate_statistics(metrics, duration) + + # Main performance log + if self.logger: + self.logger.info( + f"📊 PERFORMANCE [{timestamp}] | " + f"Points: {stats['points_saved']}/10s ({stats['points_rate']:.1f}/s) | " + f"Variables: {stats['variables_saved']} | " + f"UDP: {stats['udp_points']}/10s | " + f"CPU: {stats['cpu_avg']:.1f}% | " + f"Delay: {stats['delay_avg']:.3f}s±{stats['delay_std']:.3f}s | " + f"Lost: {stats['points_lost']} | " + f"Errors: R:{stats['read_errors']} C:{stats['csv_errors']} U:{stats['udp_errors']}" + ) + + # Warning logs for significant issues + if stats["points_lost"] > 0: + if self.logger: + self.logger.warning( + f"⚠️ DATA LOSS: {stats['points_lost']} points lost in last 10s " + f"(avg delay: {stats['delay_avg']:.3f}s)" + ) + + if stats["cpu_avg"] > 80: + if self.logger: + self.logger.warning( + f"⚠️ HIGH CPU: {stats['cpu_avg']:.1f}% average CPU usage" + ) + + if stats["read_errors"] > 0: + if self.logger: + self.logger.warning( + f"⚠️ READ ERRORS: {stats['read_errors']} read errors in last 10s" + ) + + # Log to event system + if self.event_logger: + self.event_logger.log_event( + "info", + "performance_report", + f"Performance report: {stats['points_saved']} points saved, " + f"{stats['points_lost']} lost, {stats['cpu_avg']:.1f}% CPU", + { + "duration": duration, + "points_saved": stats["points_saved"], + "points_rate": stats["points_rate"], + "variables_saved": stats["variables_saved"], + "udp_points_sent": stats["udp_points"], + "points_lost": stats["points_lost"], + "cpu_average": stats["cpu_avg"], + "cpu_max": stats["cpu_max"], + "delay_average": stats["delay_avg"], + "delay_max": stats["delay_max"], + "read_errors": stats["read_errors"], + "csv_errors": stats["csv_errors"], + "udp_errors": stats["udp_errors"], + "read_time_avg": stats["read_time_avg"], + "csv_write_time_avg": stats["csv_write_avg"], + }, + ) + + def _calculate_statistics( + self, metrics: PerformanceMetrics, duration: float + ) -> Dict[str, Any]: + """Calculate performance statistics from metrics""" + + # Points and rates + points_rate = metrics.points_saved / max(duration, 0.1) + + # CPU statistics + cpu_avg = statistics.mean(metrics.cpu_samples) if metrics.cpu_samples else 0.0 + cpu_max = max(metrics.cpu_samples) if metrics.cpu_samples else 0.0 + + # Delay statistics + delay_avg = statistics.mean(metrics.read_delays) if metrics.read_delays else 0.0 + delay_std = ( + statistics.stdev(metrics.read_delays) + if len(metrics.read_delays) > 1 + else 0.0 + ) + delay_max = max(metrics.read_delays) if metrics.read_delays else 0.0 + + # Timing statistics + read_time_avg = ( + statistics.mean(metrics.read_times) if metrics.read_times else 0.0 + ) + csv_write_avg = ( + statistics.mean(metrics.csv_write_times) if metrics.csv_write_times else 0.0 + ) + + return { + "points_saved": metrics.points_saved, + "points_rate": points_rate, + "variables_saved": metrics.variables_saved, + "udp_points": metrics.udp_points_sent, + "points_lost": metrics.points_lost, + "cpu_avg": cpu_avg, + "cpu_max": cpu_max, + "delay_avg": delay_avg, + "delay_std": delay_std, + "delay_max": delay_max, + "read_errors": metrics.read_errors, + "csv_errors": metrics.csv_errors, + "udp_errors": metrics.udp_errors, + "read_time_avg": read_time_avg, + "csv_write_avg": csv_write_avg, + } + + def get_current_stats(self) -> Dict[str, Any]: + """Get current performance statistics""" + with self.lock: + duration = time.time() - self.current_metrics.start_time + return self._calculate_statistics(self.current_metrics, duration) + + def get_historical_stats(self, windows: int = 6) -> Dict[str, Any]: + """Get historical performance statistics (last N windows)""" + with self.lock: + recent_metrics = list(self.historical_metrics)[-windows:] + + if not recent_metrics: + return {} + + # Aggregate statistics + total_points = sum(m.points_saved for m in recent_metrics) + total_variables = sum(m.variables_saved for m in recent_metrics) + total_udp = sum(m.udp_points_sent for m in recent_metrics) + total_lost = sum(m.points_lost for m in recent_metrics) + total_errors = sum( + m.read_errors + m.csv_errors + m.udp_errors for m in recent_metrics + ) + + # Average CPU + all_cpu = [] + for m in recent_metrics: + all_cpu.extend(m.cpu_samples) + avg_cpu = statistics.mean(all_cpu) if all_cpu else 0.0 + + # Average delays + all_delays = [] + for m in recent_metrics: + all_delays.extend(m.read_delays) + avg_delay = statistics.mean(all_delays) if all_delays else 0.0 + + total_duration = windows * self.report_interval + + return { + "windows": windows, + "duration_minutes": total_duration / 60, + "total_points_saved": total_points, + "total_variables_saved": total_variables, + "total_udp_sent": total_udp, + "total_points_lost": total_lost, + "total_errors": total_errors, + "points_per_second": total_points / total_duration, + "loss_rate_percent": (total_lost / max(total_points + total_lost, 1)) * 100, + "average_cpu_percent": avg_cpu, + "average_delay_seconds": avg_delay, + } diff --git a/core/plc_data_streamer.py b/core/plc_data_streamer.py index 94b6d3f..8ab69ae 100644 --- a/core/plc_data_streamer.py +++ b/core/plc_data_streamer.py @@ -13,6 +13,8 @@ try: from .event_logger import EventLogger from .instance_manager import InstanceManager from .schema_manager import ConfigSchemaManager + from .priority_manager import PriorityThreadManager, RecordingProtector + from .performance_monitor import PerformanceMonitor except ImportError: # Fallback to absolute imports (when run directly) from core.config_manager import ConfigManager @@ -21,6 +23,8 @@ except ImportError: from core.event_logger import EventLogger from core.instance_manager import InstanceManager from core.schema_manager import ConfigSchemaManager + from core.priority_manager import PriorityThreadManager, RecordingProtector + from core.performance_monitor import PerformanceMonitor class PLCDataStreamer: @@ -93,13 +97,10 @@ class PLCDataStreamer: raise def setup_logging(self): - """Configure the logging system""" - logging.basicConfig( - level=logging.INFO, - format="%(asctime)s - %(levelname)s - %(message)s", - handlers=[logging.FileHandler("plc_data.log"), logging.StreamHandler()], - ) - self.logger = logging.getLogger(__name__) + """Configure the logging system to use the rotating logger from main""" + # Use the backend logger configured in main.py + # This provides both console and rotating file logging + self.logger = logging.getLogger("backend") # PLC Connection Methods def connect_plc(self) -> bool: @@ -169,8 +170,13 @@ class PLCDataStreamer: return success - def disconnect_plc(self): - """Disconnect from PLC and stop all recording/streaming""" + def disconnect_plc(self, manual_disconnect=True): + """Disconnect from PLC and stop all recording/streaming + + Args: + manual_disconnect: True if user manually disconnected (don't auto-reconnect), + False if shutdown/crash (should auto-reconnect) + """ # Stop both CSV recording and UDP streaming self.data_streamer.stop_csv_recording() self.data_streamer.stop_udp_streaming() @@ -184,20 +190,28 @@ class PLCDataStreamer: if self.logger: self.logger.warning(f"Error deactivating dataset {dataset_id}: {e}") - # Clear any tracked datasets for auto-resume since this is manual disconnect - self.data_streamer.datasets_before_disconnection.clear() + # 🔑 CRITICAL: Only clear auto-reconnect data if this is a MANUAL disconnect + if manual_disconnect: + # Clear any tracked datasets for auto-resume since this is manual disconnect + self.data_streamer.datasets_before_disconnection.clear() + # Save state indicating user manually disconnected (don't auto-reconnect) + self.config_manager.save_system_state( + connected=False, streaming=False, active_datasets=set() + ) + disconnect_reason = "manually disconnected" + else: + # 🚀 PRESERVE auto-reconnect state for application restart + # Don't clear datasets_before_disconnection - let them auto-reconnect + # Don't save disconnected state - preserve previous "should connect" state + disconnect_reason = "application shutdown (will auto-reconnect on restart)" # Disconnect from PLC self.plc_client.disconnect() - self.config_manager.save_system_state( - connected=False, streaming=False, active_datasets=set() - ) - self.event_logger.log_event( "info", "plc_disconnection", - f"Disconnected from PLC {self.config_manager.plc_config['ip']} (stopped recording and streaming)", + f"Disconnected from PLC {self.config_manager.plc_config['ip']} ({disconnect_reason})", ) # Configuration Management Methods @@ -500,7 +514,7 @@ class PLCDataStreamer: # Status and Information Methods def get_status(self) -> Dict[str, Any]: - """Get current status of the application""" + """Get current status of the application including priority information""" status = { "plc_connected": self.plc_client.is_connected(), "streaming": self.data_streamer.is_streaming(), @@ -509,6 +523,9 @@ class PLCDataStreamer: "plc_config": self.config_manager.plc_config, "datasets_count": len(self.config_manager.datasets), "active_datasets_count": len(self.config_manager.active_datasets), + "active_datasets": list( + self.config_manager.active_datasets + ), # Convert set to list for JSON "total_variables": sum( len(self.config_manager.get_dataset_variables(dataset_id)) for dataset_id in self.config_manager.datasets.keys() @@ -522,6 +539,8 @@ class PLCDataStreamer: # Add reconnection status information "plc_reconnection": self.plc_client.get_reconnection_status(), "plc_connection_info": self.plc_client.get_connection_info(), + # 🔑 PRIORITY MANAGEMENT STATUS + "priority_protection": self.data_streamer.get_streaming_stats(), } return status @@ -750,3 +769,45 @@ class PLCDataStreamer: # DEPRECATED: save_datasets() method removed # Data is now saved directly from frontend via RJSF and API endpoints # Use reload_dataset_configuration() to reload configuration when needed + + def shutdown(self): + """🔑 CRITICAL: Safely shutdown the entire PLC data streamer system""" + if self.logger: + self.logger.info("🔥 CRITICAL: Starting PLC Data Streamer shutdown...") + + try: + # 1. Disconnect PLC first to stop all readings + if self.plc_client.is_connected(): + self.plc_client.disconnect() + if self.logger: + self.logger.info("PLC disconnected") + + # 2. Shutdown data streamer (this will handle all recording threads with priority) + if hasattr(self, "data_streamer") and self.data_streamer: + self.data_streamer.shutdown() + + # 3. Release instance lock + if hasattr(self, "instance_manager") and self.instance_manager: + self.instance_manager.release_instance_lock() + if self.logger: + self.logger.info("Instance lock released") + + if self.logger: + self.logger.info( + "🔥 CRITICAL: PLC Data Streamer shutdown completed successfully" + ) + + except Exception as e: + if self.logger: + self.logger.error( + f"🚨 CRITICAL ERROR: Error during PLC Data Streamer shutdown: {e}" + ) + raise + + def get_cached_dataset_values_safe(self, dataset_id: str): + """🔑 RATE LIMITED: Get cached values with recording protection""" + return self.data_streamer.get_cached_dataset_values_safe(dataset_id) + + def perform_csv_cleanup_safe(self): + """🔑 BACKGROUND: Perform CSV cleanup with recording protection""" + self.data_streamer.perform_csv_cleanup_safe() diff --git a/core/priority_manager.py b/core/priority_manager.py new file mode 100644 index 0000000..d108a4d --- /dev/null +++ b/core/priority_manager.py @@ -0,0 +1,342 @@ +""" +Priority Manager for PLC Data Streamer + +🔑 CORE PRINCIPLE: Recording Priority Protection +=============================================== +This module ensures that CSV recording operations have the highest priority +and are never interrupted by API processing or visualization tasks. + +Priority Levels: +- CRITICAL (10): CSV Recording threads +- HIGH (7): PLC communication +- NORMAL (5): UDP streaming, basic APIs +- LOW (3): Historical data processing +- BACKGROUND (1): Plot generation, file operations +""" + +import threading +import os +import time +import psutil +from concurrent.futures import ThreadPoolExecutor +from queue import PriorityQueue +import queue +from typing import Callable, Any, Optional +from dataclasses import dataclass, field +from enum import IntEnum + + +class Priority(IntEnum): + """Thread priority levels - higher number = higher priority""" + + BACKGROUND = 1 # Plot generation, file operations + LOW = 3 # Historical data processing + NORMAL = 5 # UDP streaming, basic APIs + HIGH = 7 # PLC communication + CRITICAL = 10 # CSV Recording threads + + +@dataclass +class PriorityTask: + """Task with priority for execution""" + + priority: Priority + func: Callable + args: tuple = field(default_factory=tuple) + kwargs: dict = field(default_factory=dict) + callback: Optional[Callable] = None + task_id: Optional[str] = None + + def __lt__(self, other): + # Higher priority number = higher priority (reversed for queue) + return self.priority > other.priority + + +class PriorityThreadManager: + """Manages thread priorities to ensure recording operations have precedence""" + + def __init__(self, logger=None): + self.logger = logger + self.recording_threads = {} # dataset_id -> thread + self.api_thread_pool = None + self.background_thread_pool = None + self._setup_thread_pools() + + # System priority adjustment + self._adjust_process_priority() + + def _setup_thread_pools(self): + """Setup separate thread pools for different priority tasks""" + # API operations pool - lower priority + self.api_thread_pool = ThreadPoolExecutor( + max_workers=2, # Limited workers to not overwhelm recording + thread_name_prefix="api_worker", + ) + + # Background operations pool - lowest priority + self.background_thread_pool = ThreadPoolExecutor( + max_workers=1, # Single worker for background tasks + thread_name_prefix="background_worker", + ) + + if self.logger: + self.logger.info( + "Priority thread pools initialized (API: 2 workers, Background: 1 worker)" + ) + + def _adjust_process_priority(self): + """Adjust current process priority to ensure recording performance""" + try: + current_process = psutil.Process() + + # Set process priority to HIGH on Windows + if os.name == "nt": # Windows + current_process.nice(psutil.HIGH_PRIORITY_CLASS) + if self.logger: + self.logger.info( + "Process priority set to HIGH for recording optimization" + ) + else: # Unix/Linux + current_process.nice(-10) # Higher priority (lower nice value) + if self.logger: + self.logger.info( + "Process nice value set to -10 for recording optimization" + ) + + except Exception as e: + if self.logger: + self.logger.warning(f"Could not adjust process priority: {e}") + + def create_recording_thread( + self, + target: Callable, + args: tuple = (), + dataset_id: str = None, + name: str = None, + ) -> threading.Thread: + """Create a high-priority thread specifically for CSV recording""" + + def priority_wrapper(): + """Wrapper that sets thread priority and executes target""" + try: + # Set thread priority to highest available + self._set_thread_priority(threading.current_thread(), Priority.CRITICAL) + + if self.logger: + thread_name = threading.current_thread().name + self.logger.info( + f"Recording thread '{thread_name}' started with CRITICAL priority" + ) + + # Execute the actual recording function + target(*args) + + except Exception as e: + if self.logger: + self.logger.error(f"Error in recording thread: {e}") + raise + + # Create thread with high priority name + thread_name = ( + name or f"recording_{dataset_id}" if dataset_id else "recording_thread" + ) + thread = threading.Thread( + target=priority_wrapper, + name=thread_name, + daemon=False, # Recording threads should NOT be daemon + ) + + # Track recording threads + if dataset_id: + self.recording_threads[dataset_id] = thread + + return thread + + def submit_api_task(self, func: Callable, *args, **kwargs) -> Any: + """Submit a task to the API thread pool (lower priority)""" + + def priority_wrapper(): + # Set lower priority for API operations + self._set_thread_priority(threading.current_thread(), Priority.NORMAL) + return func(*args, **kwargs) + + return self.api_thread_pool.submit(priority_wrapper) + + def submit_background_task(self, func: Callable, *args, **kwargs) -> Any: + """Submit a task to the background thread pool (lowest priority)""" + + def priority_wrapper(): + # Set lowest priority for background operations + self._set_thread_priority(threading.current_thread(), Priority.BACKGROUND) + return func(*args, **kwargs) + + return self.background_thread_pool.submit(priority_wrapper) + + def _set_thread_priority(self, thread: threading.Thread, priority: Priority): + """Set thread priority using OS-specific mechanisms""" + try: + if os.name == "nt": # Windows + import ctypes + from ctypes import wintypes + + # Windows thread priority constants + priority_map = { + Priority.CRITICAL: 2, # THREAD_PRIORITY_HIGHEST + Priority.HIGH: 1, # THREAD_PRIORITY_ABOVE_NORMAL + Priority.NORMAL: 0, # THREAD_PRIORITY_NORMAL + Priority.LOW: -1, # THREAD_PRIORITY_BELOW_NORMAL + Priority.BACKGROUND: -2, # THREAD_PRIORITY_LOWEST + } + + # Get thread handle and set priority + kernel32 = ctypes.windll.kernel32 + thread_handle = kernel32.GetCurrentThread() + kernel32.SetThreadPriority(thread_handle, priority_map[priority]) + + if self.logger: + self.logger.debug( + f"Thread '{thread.name}' priority set to {priority.name}" + ) + + else: # Unix/Linux + # On Unix systems, use nice values (approximate) + nice_map = { + Priority.CRITICAL: -15, + Priority.HIGH: -10, + Priority.NORMAL: 0, + Priority.LOW: 5, + Priority.BACKGROUND: 10, + } + + try: + os.nice(nice_map[priority]) + except PermissionError: + # Fall back to process-level priority if thread-level fails + pass + + except Exception as e: + if self.logger: + self.logger.debug(f"Could not set thread priority: {e}") + + def stop_recording_thread(self, dataset_id: str, timeout: float = 5.0): + """Safely stop a recording thread""" + if dataset_id in self.recording_threads: + thread = self.recording_threads[dataset_id] + + if thread.is_alive(): + # Wait for thread to finish gracefully + thread.join(timeout=timeout) + + if thread.is_alive(): + if self.logger: + self.logger.warning( + f"Recording thread for dataset '{dataset_id}' did not stop gracefully" + ) + else: + if self.logger: + self.logger.info( + f"Recording thread for dataset '{dataset_id}' stopped successfully" + ) + + del self.recording_threads[dataset_id] + + def get_recording_thread_stats(self) -> dict: + """Get statistics about recording threads""" + stats = { + "active_recording_threads": 0, + "recording_thread_names": [], + "api_pool_active": ( + len(self.api_thread_pool._threads) if self.api_thread_pool else 0 + ), + "background_pool_active": ( + len(self.background_thread_pool._threads) + if self.background_thread_pool + else 0 + ), + } + + for dataset_id, thread in self.recording_threads.items(): + if thread.is_alive(): + stats["active_recording_threads"] += 1 + stats["recording_thread_names"].append(f"{dataset_id}:{thread.name}") + + return stats + + def shutdown(self): + """Shutdown all thread pools and wait for recording threads""" + if self.logger: + self.logger.info("Shutting down priority thread manager...") + + # Stop API thread pools first (lower priority) - be aggressive + if self.api_thread_pool: + self.api_thread_pool.shutdown(wait=False, cancel_futures=True) + + if self.background_thread_pool: + self.background_thread_pool.shutdown(wait=False, cancel_futures=True) + + # Wait for recording threads to finish (highest priority) - shorter timeout + for dataset_id in list(self.recording_threads.keys()): + self.stop_recording_thread(dataset_id, timeout=2.0) # Reduced timeout + + # Force clear all threads if they didn't stop + self.recording_threads.clear() + + if self.logger: + self.logger.info("Priority thread manager shutdown complete") + + +class RecordingProtector: + """Additional protection mechanisms for recording operations""" + + def __init__(self, logger=None): + self.logger = logger + self.recording_active = False + self.api_request_count = 0 + self.max_api_requests_per_second = 10 # Limit API requests + self.last_api_reset = time.time() + + def start_recording_protection(self): + """Enable recording protection mode""" + self.recording_active = True + if self.logger: + self.logger.info( + "Recording protection mode ENABLED - API throttling active" + ) + + def stop_recording_protection(self): + """Disable recording protection mode""" + self.recording_active = False + if self.logger: + self.logger.info("Recording protection mode DISABLED") + + def check_api_rate_limit(self) -> bool: + """Check if API request should be rate-limited to protect recording""" + if not self.recording_active: + return True # No protection needed + + current_time = time.time() + + # Reset counter every second + if current_time - self.last_api_reset >= 1.0: + self.api_request_count = 0 + self.last_api_reset = current_time + + # Check rate limit + if self.api_request_count >= self.max_api_requests_per_second: + if self.logger: + self.logger.warning( + "API rate limit exceeded - protecting recording operations" + ) + return False + + self.api_request_count += 1 + return True + + def get_protection_stats(self) -> dict: + """Get protection statistics""" + return { + "recording_protection_active": self.recording_active, + "api_requests_this_second": self.api_request_count, + "api_rate_limit": self.max_api_requests_per_second, + "time_until_reset": max(0, 1.0 - (time.time() - self.last_api_reset)), + } diff --git a/core/rotating_logger.py b/core/rotating_logger.py new file mode 100644 index 0000000..92db157 --- /dev/null +++ b/core/rotating_logger.py @@ -0,0 +1,203 @@ +""" +Rotating Logger System +====================== + +Sistema de logging con rotación automática por líneas y limpieza de archivos antiguos. + +Características: +- Archivos nombrados con fecha+hora de inicio +- Máximo 10,000 líneas por archivo +- Máximo 30 archivos en directorio +- Eliminación automática de archivos más antiguos +- Logs tanto en consola como en archivo +""" + +import os +import logging +import glob +from datetime import datetime +from typing import Optional + + +class RotatingFileHandler(logging.Handler): + """Custom rotating file handler que rota por número de líneas""" + + def __init__( + self, log_dir: str = ".logs", max_lines: int = 10000, max_files: int = 30 + ): + super().__init__() + self.log_dir = log_dir + self.max_lines = max_lines + self.max_files = max_files + self.current_lines = 0 + self.current_file = None + self.current_handler = None + + # Crear directorio de logs si no existe + os.makedirs(self.log_dir, exist_ok=True) + + # Iniciar primer archivo + self._start_new_file() + + def _start_new_file(self): + """Iniciar un nuevo archivo de log""" + # Cerrar handler anterior si existe + if self.current_handler: + self.current_handler.close() + + # Generar nombre de archivo con timestamp + timestamp = datetime.now().strftime("%Y%m%d_%H%M%S") + filename = f"backend_{timestamp}.log" + self.current_file = os.path.join(self.log_dir, filename) + + # Crear nuevo handler de archivo + self.current_handler = logging.FileHandler(self.current_file, encoding="utf-8") + self.current_handler.setFormatter(self.formatter) + + # Reset contador de líneas + self.current_lines = 0 + + # Limpiar archivos antiguos + self._cleanup_old_files() + + print(f"📝 New log file started: {self.current_file}") + + def _cleanup_old_files(self): + """Eliminar archivos de log más antiguos si exceden el límite""" + # Obtener todos los archivos de log + log_pattern = os.path.join(self.log_dir, "backend_*.log") + log_files = glob.glob(log_pattern) + + # Ordenar por fecha de modificación (más antiguos primero) + log_files.sort(key=os.path.getmtime) + + # Eliminar archivos excedentes + while len(log_files) > self.max_files: + oldest_file = log_files.pop(0) + try: + os.remove(oldest_file) + print(f"🗑️ Removed old log file: {os.path.basename(oldest_file)}") + except OSError as e: + print(f"⚠️ Could not remove {oldest_file}: {e}") + + def emit(self, record): + """Emitir un registro de log""" + if not self.current_handler: + return + + # Escribir al archivo actual + self.current_handler.emit(record) + + # Incrementar contador de líneas + self.current_lines += 1 + + # Rotar si se alcanza el límite + if self.current_lines >= self.max_lines: + print( + f"🔄 Log rotation: {self.current_lines} lines reached, starting new file..." + ) + self._start_new_file() + + def close(self): + """Cerrar el handler""" + if self.current_handler: + self.current_handler.close() + super().close() + + +class DualLogger: + """Logger que escribe tanto a consola como a archivo rotativo""" + + def __init__( + self, + name: str = "backend", + log_dir: str = ".logs", + max_lines: int = 10000, + max_files: int = 30, + ): + self.logger = logging.getLogger(name) + self.logger.setLevel(logging.INFO) + + # Limpiar handlers existentes + self.logger.handlers.clear() + + # Formatter + formatter = logging.Formatter( + "%(asctime)s - %(name)s - %(levelname)s - %(message)s", + datefmt="%Y-%m-%d %H:%M:%S", + ) + + # Handler para consola + console_handler = logging.StreamHandler() + console_handler.setLevel(logging.INFO) + console_handler.setFormatter(formatter) + self.logger.addHandler(console_handler) + + # Handler para archivo rotativo + self.file_handler = RotatingFileHandler(log_dir, max_lines, max_files) + self.file_handler.setLevel(logging.INFO) + self.file_handler.setFormatter(formatter) + self.logger.addHandler(self.file_handler) + + # Mensaje de inicio + self.logger.info("=" * 60) + self.logger.info("🚀 Backend logging system started") + self.logger.info(f"📁 Log directory: {os.path.abspath(log_dir)}") + self.logger.info(f"📊 Max lines per file: {max_lines:,}") + self.logger.info(f"📦 Max files retained: {max_files}") + self.logger.info("=" * 60) + + def get_logger(self): + """Obtener el logger configurado""" + return self.logger + + def info(self, message: str): + """Log info message""" + self.logger.info(message) + + def error(self, message: str): + """Log error message""" + self.logger.error(message) + + def warning(self, message: str): + """Log warning message""" + self.logger.warning(message) + + def debug(self, message: str): + """Log debug message""" + self.logger.debug(message) + + def close(self): + """Cerrar el logger""" + self.logger.info("⏹️ Logging system shutdown") + self.file_handler.close() + + +def setup_backend_logging( + log_dir: str = ".logs", max_lines: int = 10000, max_files: int = 30 +) -> DualLogger: + """ + Configurar el sistema de logging del backend + + Args: + log_dir: Directorio donde guardar los logs (default: .logs) + max_lines: Máximo de líneas por archivo (default: 10,000) + max_files: Máximo de archivos a retener (default: 30) + + Returns: + DualLogger: Instancia del logger configurado + """ + return DualLogger("backend", log_dir, max_lines, max_files) + + +if __name__ == "__main__": + # Test del sistema de logging + logger = setup_backend_logging() + + # Simular muchos logs para probar rotación + for i in range(50): + logger.info(f"Test log message {i+1}") + if i % 10 == 9: + logger.warning(f"Warning message at iteration {i+1}") + + logger.close() diff --git a/core/streamer.py b/core/streamer.py index bf73c3b..960c760 100644 --- a/core/streamer.py +++ b/core/streamer.py @@ -10,6 +10,8 @@ from datetime import datetime from typing import Dict, Any, Optional, Set, List from pathlib import Path from .plot_manager import PlotManager +from .priority_manager import PriorityThreadManager, RecordingProtector, Priority +from .performance_monitor import PerformanceMonitor def resource_path(relative_path): @@ -45,12 +47,19 @@ class DataStreamer: """ def __init__(self, config_manager, plc_client, event_logger, logger=None): - """Initialize data streamer""" + """Initialize data streamer with priority management and performance monitoring""" self.config_manager = config_manager self.plc_client = plc_client self.event_logger = event_logger self.logger = logger + # 🔑 PRIORITY MANAGEMENT - Ensure recording has maximum priority + self.priority_manager = PriorityThreadManager(logger) + self.recording_protector = RecordingProtector(logger) + + # 📊 PERFORMANCE MONITORING - Real-time performance tracking + self.performance_monitor = PerformanceMonitor(logger, event_logger, report_interval=10.0) + # UDP streaming setup self.udp_socket = None self.udp_streaming_enabled = False # 🔑 Independent UDP control @@ -58,8 +67,8 @@ class DataStreamer: # CSV recording state (automatic when PLC connected) self.csv_recording_enabled = False - # Dataset streaming threads and files - self.dataset_threads = {} # dataset_id -> thread object + # Dataset streaming threads and files - now managed by priority system + self.dataset_threads = {} # dataset_id -> thread object (HIGH PRIORITY) self.dataset_csv_files = {} # dataset_id -> file handle self.dataset_csv_writers = {} # dataset_id -> csv writer self.dataset_csv_hours = {} # dataset_id -> current hour @@ -588,13 +597,16 @@ class DataStreamer: ) def dataset_streaming_loop(self, dataset_id: str): - """Streaming loop for a specific dataset - handles both CSV and UDP""" + """🔑 HIGH PRIORITY: Streaming loop for CSV recording - CRITICAL PRIORITY THREAD with performance monitoring""" dataset_info = self.config_manager.datasets[dataset_id] interval = self.config_manager.get_dataset_sampling_interval(dataset_id) + + # 📊 Register dataset with performance monitor + self.performance_monitor.set_dataset_interval(dataset_id, interval) if self.logger: self.logger.info( - f"Dataset '{dataset_info['name']}' loop started (interval: {interval}s)" + f"🔥 CRITICAL PRIORITY: Dataset '{dataset_info['name']}' recording loop started (interval: {interval}s)" ) consecutive_errors = 0 @@ -604,103 +616,128 @@ class DataStreamer: dataset_id in self.config_manager.active_datasets and self.plc_client.is_connected() ): + loop_start_time = time.time() + read_success = False + read_time = 0.0 + csv_write_time = 0.0 + variables_count = 0 + try: - start_time = time.time() - - # Read variables for this dataset (serialized across datasets) - dataset_variables = self.config_manager.get_dataset_variables( - dataset_id - ) + # 📋 CRITICAL SECTION: PLC READ with timing and error tracking + dataset_variables = self.config_manager.get_dataset_variables(dataset_id) + variables_count = len(dataset_variables) + + # Measure read operation time + read_start = time.time() + # Ensure entire dataset read is atomic w.r.t. other datasets with self.plc_client.io_lock: - all_data = self.read_dataset_variables( - dataset_id, dataset_variables - ) + all_data = self.read_dataset_variables(dataset_id, dataset_variables) + + read_time = time.time() - read_start + read_success = bool(all_data) if all_data: consecutive_errors = 0 - # 📝 CSV Recording: Always write if enabled (automatic) + # 📝 CSV Recording: ALWAYS FIRST - HIGHEST PRIORITY with timing if self.csv_recording_enabled: - self.write_dataset_csv_data(dataset_id, all_data) + csv_start = time.time() + try: + self.write_dataset_csv_data(dataset_id, all_data) + csv_write_time = time.time() - csv_start + + # 📊 Record successful CSV write + self.performance_monitor.record_csv_write(dataset_id, csv_write_time, success=True) + + except Exception as csv_error: + csv_write_time = time.time() - csv_start + + # 📊 Record CSV write error + self.performance_monitor.record_csv_write(dataset_id, csv_write_time, success=False) + + if self.logger: + self.logger.error(f"🚨 CSV WRITE ERROR for dataset '{dataset_info['name']}': {csv_error}") - # 📡 UDP Streaming: Only if UDP streaming is enabled (manual) + # 📡 UDP Streaming: Lower priority - only if enabled if self.udp_streaming_enabled: - # Get filtered data for streaming - only variables that are in streaming_variables list AND have streaming=true - streaming_variables = dataset_info.get( - "streaming_variables", [] + # Use background thread for UDP to not block recording + self.priority_manager.submit_background_task( + self._handle_udp_streaming, dataset_id, dataset_info, all_data ) - dataset_vars_config = dataset_info.get("variables", {}) - streaming_data = { - name: value - for name, value in all_data.items() - if name in streaming_variables - and dataset_vars_config.get(name, {}).get( - "streaming", False - ) - } - # Send filtered data to PlotJuggler - if streaming_data: - self.send_to_plotjuggler(streaming_data) - - # 📈 PLOT MANAGER: Update all active plot sessions with cache data + # 📈 PLOT MANAGER: Background priority - update plots without blocking if self.plot_manager.get_active_sessions_count() > 0: - self.plot_manager.update_data(dataset_id, all_data) - - # Log data - timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S.%f")[:-3] - if self.logger: - csv_count = len(all_data) if self.csv_recording_enabled else 0 - udp_count = 0 - if self.udp_streaming_enabled: - streaming_variables = dataset_info.get( - "streaming_variables", [] - ) - dataset_vars_config = dataset_info.get("variables", {}) - udp_count = len( - [ - name - for name in all_data.keys() - if name in streaming_variables - and dataset_vars_config.get(name, {}).get( - "streaming", False - ) - ] - ) - - self.logger.info( - f"[{timestamp}] Dataset '{dataset_info['name']}': CSV: {csv_count} vars, UDP: {udp_count} vars" + self.priority_manager.submit_background_task( + self.plot_manager.update_data, dataset_id, all_data ) + else: consecutive_errors += 1 if consecutive_errors >= max_consecutive_errors: self.event_logger.log_event( "error", "dataset_loop_error", - f"Multiple consecutive read failures for dataset '{dataset_info['name']}' ({consecutive_errors}). Stopping dataset.", + f"� CRITICAL: Multiple consecutive read failures for dataset '{dataset_info['name']}' ({consecutive_errors}). Stopping dataset.", { "dataset_id": dataset_id, "consecutive_errors": consecutive_errors, + "priority": "CRITICAL" }, ) break + # � Calculate timing and delay metrics + loop_end_time = time.time() + total_loop_time = loop_end_time - loop_start_time + expected_end_time = loop_start_time + interval + + # Calculate delay (how much we're behind schedule) + delay = max(0.0, loop_end_time - expected_end_time) + + # 📊 Record performance metrics + self.performance_monitor.record_dataset_read( + dataset_id=dataset_id, + read_time=read_time, + variables_count=variables_count, + success=read_success, + delay=delay + ) + # Maintain sampling interval - elapsed = time.time() - start_time - sleep_time = max(0, interval - elapsed) - time.sleep(sleep_time) + sleep_time = max(0, interval - total_loop_time) + if sleep_time > 0: + time.sleep(sleep_time) + elif delay > interval * 0.1: # Log if delay is > 10% of interval + if self.logger: + self.logger.warning( + f"⏰ TIMING WARNING: Dataset '{dataset_info['name']}' loop overrun by {delay:.3f}s " + f"(read: {read_time:.3f}s, csv: {csv_write_time:.3f}s, total: {total_loop_time:.3f}s)" + ) except Exception as e: consecutive_errors += 1 + + # 📊 Record read error + self.performance_monitor.record_dataset_read( + dataset_id=dataset_id, + read_time=read_time, + variables_count=variables_count, + success=False, + delay=0.0 + ) + self.event_logger.log_event( "error", "dataset_loop_error", - f"Error in dataset '{dataset_info['name']}' loop: {str(e)}", + f"🚨 CRITICAL ERROR: Dataset '{dataset_info['name']}' recording loop error: {str(e)}", { "dataset_id": dataset_id, "error": str(e), "consecutive_errors": consecutive_errors, + "priority": "CRITICAL", + "read_time": read_time, + "variables_count": variables_count }, ) @@ -708,10 +745,11 @@ class DataStreamer: self.event_logger.log_event( "error", "dataset_loop_error", - f"Too many consecutive errors for dataset '{dataset_info['name']}'. Stopping dataset.", + f"🚨 CRITICAL FAILURE: Too many consecutive errors for dataset '{dataset_info['name']}'. Stopping dataset.", { "dataset_id": dataset_id, "consecutive_errors": consecutive_errors, + "priority": "CRITICAL" }, ) break @@ -721,10 +759,47 @@ class DataStreamer: # 🔑 FIXED: Do NOT call stop_dataset_streaming from within the loop # The thread will be cleaned up externally when needed if self.logger: - self.logger.info(f"Dataset '{dataset_info['name']}' loop ended") + self.logger.info(f"🔥 CRITICAL: Dataset '{dataset_info['name']}' recording loop ended") + + def _handle_udp_streaming(self, dataset_id: str, dataset_info: dict, all_data: dict): + """Handle UDP streaming in background thread (lower priority) with performance tracking""" + try: + # Get filtered data for streaming - only variables that are in streaming_variables list AND have streaming=true + streaming_variables = dataset_info.get("streaming_variables", []) + dataset_vars_config = dataset_info.get("variables", {}) + streaming_data = { + name: value + for name, value in all_data.items() + if name in streaming_variables + and dataset_vars_config.get(name, {}).get("streaming", False) + } + + # Send filtered data to PlotJuggler + if streaming_data: + try: + self.send_to_plotjuggler(streaming_data) + + # 📊 Record successful UDP send + self.performance_monitor.record_udp_send(len(streaming_data), success=True) + + except Exception as udp_error: + # 📊 Record UDP send error + self.performance_monitor.record_udp_send(len(streaming_data), success=False) + + if self.logger: + self.logger.warning(f"UDP streaming error for dataset '{dataset_info['name']}': {udp_error}") + + if self.logger: + udp_count = len(streaming_data) + self.logger.debug( + f"📡 Background: UDP sent {udp_count} vars for dataset '{dataset_info['name']}'" + ) + except Exception as e: + if self.logger: + self.logger.warning(f"UDP streaming error (non-critical): {e}") def start_dataset_streaming(self, dataset_id: str): - """Start streaming thread for a specific dataset""" + """🔑 CRITICAL: Start HIGH PRIORITY recording thread for a specific dataset""" if dataset_id not in self.config_manager.datasets: return False @@ -735,7 +810,7 @@ class DataStreamer: if self.logger: dataset_name = self.config_manager.datasets[dataset_id]["name"] self.logger.info( - f"Dataset '{dataset_name}' thread is already running, skipping creation" + f"🔥 CRITICAL: Dataset '{dataset_name}' recording thread is already running, skipping creation" ) return True # Already running and alive else: @@ -743,15 +818,18 @@ class DataStreamer: if self.logger: dataset_name = self.config_manager.datasets[dataset_id]["name"] self.logger.info( - f"Cleaning up dead thread for dataset '{dataset_name}'" + f"🔥 CRITICAL: Cleaning up dead recording thread for dataset '{dataset_name}'" ) del self.dataset_threads[dataset_id] - # Create and start thread for this dataset - thread = threading.Thread( - target=self.dataset_streaming_loop, args=(dataset_id,) + # 🔑 CRITICAL: Create HIGH PRIORITY thread for recording using priority manager + thread = self.priority_manager.create_recording_thread( + target=self.dataset_streaming_loop, + args=(dataset_id,), + dataset_id=dataset_id, + name=f"recording_{dataset_id}" ) - thread.daemon = True + self.dataset_threads[dataset_id] = thread thread.start() @@ -760,19 +838,19 @@ class DataStreamer: if self.logger: self.logger.info( - f"Started streaming for dataset '{dataset_info['name']}' (interval: {interval}s)" + f"🔥 CRITICAL PRIORITY: Started recording thread for dataset '{dataset_info['name']}' (interval: {interval}s)" ) return True def stop_dataset_streaming(self, dataset_id: str): - """Stop streaming thread for a specific dataset""" + """🔑 CRITICAL: Stop recording thread for a specific dataset safely""" if dataset_id in self.dataset_threads: - # The thread will detect this and stop - thread = self.dataset_threads[dataset_id] - # 🔑 FIXED: Check if we're not trying to join the current thread - if thread.is_alive() and thread != threading.current_thread(): - thread.join(timeout=2) - del self.dataset_threads[dataset_id] + # Use priority manager to safely stop the recording thread + self.priority_manager.stop_recording_thread(dataset_id, timeout=5.0) + + # Clean up the reference + if dataset_id in self.dataset_threads: + del self.dataset_threads[dataset_id] # Close CSV file if open if dataset_id in self.dataset_csv_files: @@ -786,7 +864,7 @@ class DataStreamer: dataset_info = self.config_manager.datasets.get(dataset_id, {}) if self.logger: self.logger.info( - f"Stopped streaming for dataset '{dataset_info.get('name', dataset_id)}'" + f"🔥 CRITICAL: Stopped recording thread for dataset '{dataset_info.get('name', dataset_id)}'" ) def activate_dataset(self, dataset_id: str): @@ -838,9 +916,9 @@ class DataStreamer: {"dataset_id": dataset_id}, ) - # 🔑 NEW: CSV Recording Methods (Automatic) + # 🔑 NEW: CSV Recording Methods (Automatic - HIGHEST PRIORITY) def start_csv_recording(self) -> bool: - """Start automatic CSV recording for all datasets with variables""" + """🔥 CRITICAL: Start automatic CSV recording with MAXIMUM PRIORITY and performance monitoring""" if not self.plc_client.is_connected(): self.event_logger.log_event( "error", @@ -857,6 +935,12 @@ class DataStreamer: ) return False + # 🔥 ENABLE RECORDING PROTECTION MODE + self.recording_protector.start_recording_protection() + + # 📊 START PERFORMANCE MONITORING + self.performance_monitor.start_monitoring() + # Activate all datasets that have variables for CSV recording activated_count = 0 for dataset_id, dataset_info in self.config_manager.datasets.items(): @@ -876,6 +960,8 @@ class DataStreamer: "csv_recording_error", "Cannot start CSV recording: No datasets with variables configured", ) + # Stop monitoring if no datasets activated + self.performance_monitor.stop_monitoring() return False self.csv_recording_enabled = True @@ -888,17 +974,26 @@ class DataStreamer: self.event_logger.log_event( "info", "csv_recording_started", - f"CSV recording started: {activated_count} datasets activated", + f"🔥 CRITICAL PRIORITY: CSV recording started with MAXIMUM PRIORITY and performance monitoring: {activated_count} datasets activated", { "activated_datasets": activated_count, "total_datasets": len(self.config_manager.datasets), + "priority": "CRITICAL", + "recording_protection": True, + "performance_monitoring": True }, ) return True def stop_csv_recording(self): - """Stop CSV recording but keep dataset threads for potential UDP streaming""" + """🔥 CRITICAL: Stop CSV recording safely with performance monitoring""" self.csv_recording_enabled = False + + # 🔥 DISABLE RECORDING PROTECTION MODE + self.recording_protector.stop_recording_protection() + + # 📊 STOP PERFORMANCE MONITORING + self.performance_monitor.stop_monitoring() # Close all CSV files but keep threads running for dataset_id in list(self.dataset_csv_files.keys()): @@ -919,7 +1014,11 @@ class DataStreamer: self.event_logger.log_event( "info", "csv_recording_stopped", - "CSV recording stopped (dataset threads continue for UDP streaming)", + "🔥 CRITICAL: CSV recording stopped (dataset threads continue for UDP streaming)", + { + "recording_protection": False, + "performance_monitoring": False + } ) # 🔑 NEW: UDP Streaming Methods (Manual) @@ -1146,14 +1245,60 @@ class DataStreamer: ) def get_streaming_stats(self) -> Dict[str, Any]: - """Get streaming statistics""" - return { + """Get streaming statistics including priority and performance information""" + stats = { "streaming": self.streaming, "active_datasets": len(self.config_manager.active_datasets), "active_threads": len(self.dataset_threads), "open_csv_files": len(self.dataset_csv_files), "udp_socket_active": self.udp_socket is not None, + # 🔑 PRIORITY STATS + "priority_stats": self.priority_manager.get_recording_thread_stats(), + "recording_protection": self.recording_protector.get_protection_stats(), + "csv_recording_enabled": self.csv_recording_enabled, + # 📊 PERFORMANCE STATS + "performance_current": self.performance_monitor.get_current_stats(), + "performance_historical": self.performance_monitor.get_historical_stats(windows=6), # Last minute } + return stats + + def get_cached_dataset_values_safe(self, dataset_id: str): + """🔑 RATE LIMITED: Get cached values with API rate limiting protection""" + # Check rate limit to protect recording operations + if not self.recording_protector.check_api_rate_limit(): + return { + "success": False, + "error": "API rate limit exceeded - protecting recording operations", + "error_type": "rate_limited", + "message": "Too many API requests - recording operations have priority", + "retry_after": 1.0 + } + + # Use background thread for cache access to not block recording + future = self.priority_manager.submit_api_task( + self.get_cached_dataset_values, dataset_id + ) + + try: + return future.result(timeout=2.0) # 2 second timeout + except Exception as e: + return { + "success": False, + "error": f"API timeout or error: {str(e)}", + "error_type": "api_timeout", + "message": "API request timed out - recording operations have priority" + } + + def perform_csv_cleanup_safe(self): + """🔑 BACKGROUND: Perform CSV cleanup in background thread""" + if self.csv_recording_enabled: + # Don't run cleanup while recording is active - protect recording + if self.logger: + self.logger.info("Skipping CSV cleanup - recording is active (protecting recording operations)") + return + + # Run cleanup in background thread + self.priority_manager.submit_background_task(self.perform_csv_cleanup) def _on_plc_reconnected(self): """Callback method called when PLC reconnects successfully""" @@ -1333,3 +1478,50 @@ class DataStreamer: ) else: self.logger.warning("No active datasets found to track for auto-resume") + + def shutdown(self): + """🔑 CRITICAL: Safely shutdown all streaming operations with priority protection and performance monitoring""" + if self.logger: + self.logger.info("🔥 CRITICAL: Starting safe shutdown of data streamer...") + + try: + # 1. Stop performance monitoring first + self.performance_monitor.stop_monitoring() + + # 2. Stop CSV recording first (graceful stop) + if self.csv_recording_enabled: + self.stop_csv_recording() + + # 3. Stop UDP streaming + if self.udp_streaming_enabled: + self.stop_udp_streaming() + + # 4. Stop all dataset streaming threads using priority manager + active_datasets = list(self.dataset_threads.keys()) + for dataset_id in active_datasets: + self.stop_dataset_streaming(dataset_id) + + # 5. Shutdown priority manager (will wait for all recording threads) + self.priority_manager.shutdown() + + # 6. Clear all cached data + self.clear_cached_values() + + # 7. Close any remaining files + for dataset_id in list(self.dataset_csv_files.keys()): + try: + self.dataset_csv_files[dataset_id].close() + except: + pass + + self.dataset_csv_files.clear() + self.dataset_csv_writers.clear() + self.dataset_csv_hours.clear() + + if self.logger: + self.logger.info("🔥 CRITICAL: Data streamer shutdown completed successfully") + + except Exception as e: + if self.logger: + self.logger.error(f"🚨 CRITICAL ERROR: Error during data streamer shutdown: {e}") + raise diff --git a/frontend/src/pages/Dashboard.jsx b/frontend/src/pages/Dashboard.jsx index 38dd5e1..9c7ae3e 100644 --- a/frontend/src/pages/Dashboard.jsx +++ b/frontend/src/pages/Dashboard.jsx @@ -457,7 +457,14 @@ function StatusBar({ status, isConnected, isLeader }) { status: 'info', duration: 2000 }) - // El polling coordinado actualizará automáticamente el estado + // 🔥 IMMEDIATELY update frontend state after successful disconnect + if (result.success) { + setPlcConnected(false) + setStreaming(false) + setCsvRecording(false) + // Force refresh status to sync with backend + loadStatus() + } } catch (error) { toast({ title: '❌ Failed to disconnect PLC', diff --git a/main.py b/main.py index efcc629..8e5752d 100644 --- a/main.py +++ b/main.py @@ -8,14 +8,25 @@ from flask import ( from flask_cors import CORS import json import time +import signal +import sys from datetime import datetime, timedelta, timezone import os -import sys import logging -# Configure logging to show only errors for cleaner historical data logs -logging.basicConfig(level=logging.ERROR) -# Reduce Flask's request logging to ERROR level only +# 📝 ROTATING LOGGER SYSTEM +from core.rotating_logger import setup_backend_logging + +# 📝 Setup rotating logger system +# This will log to both console and .logs/ directory with automatic rotation +backend_logger = setup_backend_logging( + log_dir=".logs", # Directory for log files + max_lines=10000, # Max lines per file + max_files=30 # Max files to retain +) + +# Configure standard logging to use our rotating system +# Reduce Flask's request logging to ERROR level only (keep logs clean) logging.getLogger('werkzeug').setLevel(logging.ERROR) try: @@ -467,16 +478,16 @@ def update_csv_config(): @app.route("/api/csv/cleanup", methods=["POST"]) def trigger_csv_cleanup(): - """Manually trigger CSV cleanup""" + """🔑 BACKGROUND: Manually trigger CSV cleanup with recording protection""" error_response = check_streamer_initialized() if error_response: return error_response try: - # Perform cleanup - streamer.streamer.perform_csv_cleanup() + # 🔑 PROTECTED: Perform cleanup with recording protection + streamer.perform_csv_cleanup_safe() return jsonify( - {"success": True, "message": "CSV cleanup completed successfully"} + {"success": True, "message": "CSV cleanup queued in background (recording protection active)"} ) except Exception as e: @@ -582,8 +593,17 @@ def connect_plc(): @app.route("/api/plc/disconnect", methods=["POST"]) def disconnect_plc(): """Disconnect from PLC""" - streamer.disconnect_plc() - return jsonify({"success": True, "message": "Disconnected from PLC"}) + streamer.disconnect_plc(manual_disconnect=True) # User manually disconnected + # Return updated status to ensure frontend gets correct state + return jsonify({ + "success": True, + "message": "Disconnected from PLC", + "status": { + "plc_connected": False, + "streaming": False, + "csv_recording": False + } + }) @app.route("/api/variables", methods=["POST"]) @@ -829,7 +849,7 @@ def get_streaming_variables(): @app.route("/api/datasets//variables/values", methods=["GET"]) def get_dataset_variable_values(dataset_id): - """Get current values of all variables in a dataset - CACHE ONLY""" + """🔑 RATE LIMITED: Get current values of all variables in a dataset - CACHE ONLY with recording protection""" error_response = check_streamer_initialized() if error_response: return error_response @@ -897,7 +917,7 @@ def get_dataset_variable_values(dataset_id): } ) - # Get cached values - this is the ONLY source of data according to application principles + # Check if cached values are available if not streamer.has_cached_values(dataset_id): return jsonify( { @@ -918,8 +938,16 @@ def get_dataset_variable_values(dataset_id): } ) - # Get cached values (the ONLY valid source according to application design) - read_result = streamer.get_cached_dataset_values(dataset_id) + # 🔑 PROTECTED: Get cached values with rate limiting and recording protection + read_result = streamer.get_cached_dataset_values_safe(dataset_id) + + # Handle rate limiting response + if not read_result.get("success", False) and read_result.get("error_type") == "rate_limited": + return jsonify(read_result), 429 # Too Many Requests + + # Handle API timeout response + if not read_result.get("success", False) and read_result.get("error_type") == "api_timeout": + return jsonify(read_result), 503 # Service Unavailable # Convert timestamp from ISO format to readable format for consistency if read_result.get("timestamp"): @@ -2411,6 +2439,66 @@ def get_status(): return jsonify(streamer.get_status()) +@app.route("/api/priority/status") +def get_priority_status(): + """🔑 Get detailed priority and recording protection status""" + error_response = check_streamer_initialized() + if error_response: + return error_response + + try: + priority_stats = streamer.data_streamer.get_streaming_stats() + return jsonify({ + "success": True, + "priority_protection": priority_stats, + "message": "Priority protection ensures CSV recording has maximum priority over API operations" + }) + except Exception as e: + return jsonify({"success": False, "error": str(e)}), 500 + + +@app.route("/api/performance/current") +def get_current_performance(): + """📊 Get current performance metrics (last 10 seconds)""" + error_response = check_streamer_initialized() + if error_response: + return error_response + + try: + current_stats = streamer.data_streamer.performance_monitor.get_current_stats() + return jsonify({ + "success": True, + "current_performance": current_stats, + "message": "Current performance metrics for active recording operations" + }) + except Exception as e: + return jsonify({"success": False, "error": str(e)}), 500 + + +@app.route("/api/performance/historical") +def get_historical_performance(): + """📊 Get historical performance metrics""" + error_response = check_streamer_initialized() + if error_response: + return error_response + + try: + # Get query parameters + windows = int(request.args.get('windows', 6)) # Default: last minute (6 * 10s) + windows = min(max(windows, 1), 60) # Limit between 1 and 60 windows + + historical_stats = streamer.data_streamer.performance_monitor.get_historical_stats(windows) + return jsonify({ + "success": True, + "historical_performance": historical_stats, + "windows_requested": windows, + "duration_minutes": windows * 10 / 60, + "message": f"Historical performance metrics for last {windows} windows ({windows*10} seconds)" + }) + except Exception as e: + return jsonify({"success": False, "error": str(e)}), 500 + + @app.route("/api/plc/reconnection/status") def get_plc_reconnection_status(): """Get detailed PLC reconnection status""" @@ -2723,15 +2811,34 @@ def graceful_shutdown(): print("\n⏹️ Performing graceful shutdown...") try: streamer.stop_streaming() - streamer.disconnect_plc() + # 🚀 PRESERVE auto-reconnect state: Don't clear reconnection data + streamer.disconnect_plc(manual_disconnect=False) # Keep auto-reconnect state + # 🔑 PRIORITY: Shutdown priority manager and performance monitor + if hasattr(streamer.data_streamer, 'priority_manager'): + streamer.data_streamer.priority_manager.shutdown() + if hasattr(streamer.data_streamer, 'performance_monitor'): + streamer.data_streamer.performance_monitor.stop_monitoring() streamer.release_instance_lock() + # 📝 Close rotating logger system + backend_logger.close() print("✅ Shutdown completed successfully") except Exception as e: print(f"⚠️ Error during shutdown: {e}") +def signal_handler(sig, frame): + """Handle interrupt signals (Ctrl+C)""" + print(f"\n🛑 Received signal {sig}...") + graceful_shutdown() + sys.exit(0) + + def main(): """Main application entry point with error handling and recovery""" + # Setup signal handlers for graceful shutdown + signal.signal(signal.SIGINT, signal_handler) + signal.signal(signal.SIGTERM, signal_handler) + max_retries = 3 retry_count = 0 @@ -2745,7 +2852,7 @@ def main(): global streamer # Start Flask application - app.run(debug=False, host="0.0.0.0", port=5050, use_reloader=False) + app.run(debug=False, host="0.0.0.0", port=5050, use_reloader=False, threaded=True) # If we reach here, the server stopped normally break diff --git a/system_state.json b/system_state.json index d46ed0e..6a4f67a 100644 --- a/system_state.json +++ b/system_state.json @@ -4,11 +4,10 @@ "should_stream": false, "active_datasets": [ "DAR", - "Test", "Fast" ] }, "auto_recovery_enabled": true, - "last_update": "2025-08-16T16:41:43.854840", + "last_update": "2025-08-16T18:34:19.713675", "plotjuggler_path": "C:\\Program Files\\PlotJuggler\\plotjuggler.exe" } \ No newline at end of file