diff --git a/application_events.json b/application_events.json index 1d69c4b..87ecd1c 100644 --- a/application_events.json +++ b/application_events.json @@ -1,1155 +1,5 @@ { "events": [ - { - "timestamp": "2025-08-18T18:04:27.624922", - "level": "info", - "event_type": "performance_report", - "message": "Performance report: 0 points saved, 0 lost, 0.0% CPU", - "details": { - "duration": 10.035651206970215, - "points_saved": 0, - "points_rate": 0.0, - "variables_saved": 0, - "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.0, - "csv_write_time_avg": 0.0 - } - }, - { - "timestamp": "2025-08-18T18:04:37.654650", - "level": "info", - "event_type": "performance_report", - "message": "Performance report: 0 points saved, 0 lost, 0.2% CPU", - "details": { - "duration": 10.029727220535278, - "points_saved": 0, - "points_rate": 0.0, - "variables_saved": 0, - "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.0, - "csv_write_time_avg": 0.0 - } - }, - { - "timestamp": "2025-08-18T18:04:47.691231", - "level": "info", - "event_type": "performance_report", - "message": "Performance report: 0 points saved, 0 lost, 0.3% CPU", - "details": { - "duration": 10.036581039428711, - "points_saved": 0, - "points_rate": 0.0, - "variables_saved": 0, - "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.0, - "csv_write_time_avg": 0.0 - } - }, - { - "timestamp": "2025-08-18T18:04:57.720500", - "level": "info", - "event_type": "performance_report", - "message": "Performance report: 0 points saved, 0 lost, 0.0% CPU", - "details": { - "duration": 10.029268980026245, - "points_saved": 0, - "points_rate": 0.0, - "variables_saved": 0, - "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.0, - "csv_write_time_avg": 0.0 - } - }, - { - "timestamp": "2025-08-18T18:05:07.754993", - "level": "info", - "event_type": "performance_report", - "message": "Performance report: 0 points saved, 0 lost, 0.2% CPU", - "details": { - "duration": 10.03449273109436, - "points_saved": 0, - "points_rate": 0.0, - "variables_saved": 0, - "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.0, - "csv_write_time_avg": 0.0 - } - }, - { - "timestamp": "2025-08-18T18:05:17.781291", - "level": "info", - "event_type": "performance_report", - "message": "Performance report: 0 points saved, 0 lost, 0.2% CPU", - "details": { - "duration": 10.02629804611206, - "points_saved": 0, - "points_rate": 0.0, - "variables_saved": 0, - "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.0, - "csv_write_time_avg": 0.0 - } - }, - { - "timestamp": "2025-08-18T18:05:27.809858", - "level": "info", - "event_type": "performance_report", - "message": "Performance report: 0 points saved, 0 lost, 0.0% CPU", - "details": { - "duration": 10.028567790985107, - "points_saved": 0, - "points_rate": 0.0, - "variables_saved": 0, - "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.0, - "csv_write_time_avg": 0.0 - } - }, - { - "timestamp": "2025-08-18T18:05:37.848931", - "level": "info", - "event_type": "performance_report", - "message": "Performance report: 0 points saved, 0 lost, 0.2% CPU", - "details": { - "duration": 10.039072275161743, - "points_saved": 0, - "points_rate": 0.0, - "variables_saved": 0, - "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.0, - "csv_write_time_avg": 0.0 - } - }, - { - "timestamp": "2025-08-18T18:05:47.879615", - "level": "info", - "event_type": "performance_report", - "message": "Performance report: 0 points saved, 0 lost, 0.0% CPU", - "details": { - "duration": 10.030684471130371, - "points_saved": 0, - "points_rate": 0.0, - "variables_saved": 0, - "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.0, - "csv_write_time_avg": 0.0 - } - }, - { - "timestamp": "2025-08-18T18:05:57.909314", - "level": "info", - "event_type": "performance_report", - "message": "Performance report: 0 points saved, 0 lost, 0.0% CPU", - "details": { - "duration": 10.029699087142944, - "points_saved": 0, - "points_rate": 0.0, - "variables_saved": 0, - "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.0, - "csv_write_time_avg": 0.0 - } - }, - { - "timestamp": "2025-08-18T18:06:07.938777", - "level": "info", - "event_type": "performance_report", - "message": "Performance report: 0 points saved, 0 lost, 0.2% CPU", - "details": { - "duration": 10.029463291168213, - "points_saved": 0, - "points_rate": 0.0, - "variables_saved": 0, - "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.0, - "csv_write_time_avg": 0.0 - } - }, - { - "timestamp": "2025-08-18T18:06:17.967769", - "level": "info", - "event_type": "performance_report", - "message": "Performance report: 0 points saved, 0 lost, 0.2% CPU", - "details": { - "duration": 10.028991222381592, - "points_saved": 0, - "points_rate": 0.0, - "variables_saved": 0, - "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.0, - "csv_write_time_avg": 0.0 - } - }, - { - "timestamp": "2025-08-18T18:06:27.997601", - "level": "info", - "event_type": "performance_report", - "message": "Performance report: 0 points saved, 0 lost, 0.0% CPU", - "details": { - "duration": 10.029832601547241, - "points_saved": 0, - "points_rate": 0.0, - "variables_saved": 0, - "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.0, - "csv_write_time_avg": 0.0 - } - }, - { - "timestamp": "2025-08-18T18:06:38.039721", - "level": "info", - "event_type": "performance_report", - "message": "Performance report: 0 points saved, 0 lost, 0.2% CPU", - "details": { - "duration": 10.04211974143982, - "points_saved": 0, - "points_rate": 0.0, - "variables_saved": 0, - "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.0, - "csv_write_time_avg": 0.0 - } - }, - { - "timestamp": "2025-08-18T18:06:48.069105", - "level": "info", - "event_type": "performance_report", - "message": "Performance report: 0 points saved, 0 lost, 0.0% CPU", - "details": { - "duration": 10.029384136199951, - "points_saved": 0, - "points_rate": 0.0, - "variables_saved": 0, - "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.0, - "csv_write_time_avg": 0.0 - } - }, - { - "timestamp": "2025-08-18T18:06:58.104301", - "level": "info", - "event_type": "performance_report", - "message": "Performance report: 0 points saved, 0 lost, 0.0% CPU", - "details": { - "duration": 10.035195589065552, - "points_saved": 0, - "points_rate": 0.0, - "variables_saved": 0, - "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.0, - "csv_write_time_avg": 0.0 - } - }, - { - "timestamp": "2025-08-18T18:07:08.152487", - "level": "info", - "event_type": "performance_report", - "message": "Performance report: 0 points saved, 0 lost, 0.5% CPU", - "details": { - "duration": 10.048186302185059, - "points_saved": 0, - "points_rate": 0.0, - "variables_saved": 0, - "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.0, - "csv_write_time_avg": 0.0 - } - }, - { - "timestamp": "2025-08-18T18:07:18.179211", - "level": "info", - "event_type": "performance_report", - "message": "Performance report: 0 points saved, 0 lost, 0.2% CPU", - "details": { - "duration": 10.026723384857178, - "points_saved": 0, - "points_rate": 0.0, - "variables_saved": 0, - "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.0, - "csv_write_time_avg": 0.0 - } - }, - { - "timestamp": "2025-08-18T18:07:28.207698", - "level": "info", - "event_type": "performance_report", - "message": "Performance report: 0 points saved, 0 lost, 0.0% CPU", - "details": { - "duration": 10.028487205505371, - "points_saved": 0, - "points_rate": 0.0, - "variables_saved": 0, - "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.0, - "csv_write_time_avg": 0.0 - } - }, - { - "timestamp": "2025-08-18T18:07:38.243239", - "level": "info", - "event_type": "performance_report", - "message": "Performance report: 0 points saved, 0 lost, 0.0% CPU", - "details": { - "duration": 10.035541534423828, - "points_saved": 0, - "points_rate": 0.0, - "variables_saved": 0, - "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.0, - "csv_write_time_avg": 0.0 - } - }, - { - "timestamp": "2025-08-18T18:07:48.288742", - "level": "info", - "event_type": "performance_report", - "message": "Performance report: 0 points saved, 0 lost, 0.0% CPU", - "details": { - "duration": 10.045502424240112, - "points_saved": 0, - "points_rate": 0.0, - "variables_saved": 0, - "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.0, - "csv_write_time_avg": 0.0 - } - }, - { - "timestamp": "2025-08-18T18:07:58.319596", - "level": "info", - "event_type": "performance_report", - "message": "Performance report: 0 points saved, 0 lost, 0.0% CPU", - "details": { - "duration": 10.03085446357727, - "points_saved": 0, - "points_rate": 0.0, - "variables_saved": 0, - "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.0, - "csv_write_time_avg": 0.0 - } - }, - { - "timestamp": "2025-08-18T18:08:08.349488", - "level": "info", - "event_type": "performance_report", - "message": "Performance report: 0 points saved, 0 lost, 0.2% CPU", - "details": { - "duration": 10.02989149093628, - "points_saved": 0, - "points_rate": 0.0, - "variables_saved": 0, - "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.0, - "csv_write_time_avg": 0.0 - } - }, - { - "timestamp": "2025-08-18T18:08:18.380678", - "level": "info", - "event_type": "performance_report", - "message": "Performance report: 0 points saved, 0 lost, 0.0% CPU", - "details": { - "duration": 10.031190156936646, - "points_saved": 0, - "points_rate": 0.0, - "variables_saved": 0, - "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.0, - "csv_write_time_avg": 0.0 - } - }, - { - "timestamp": "2025-08-18T18:08:28.408005", - "level": "info", - "event_type": "performance_report", - "message": "Performance report: 0 points saved, 0 lost, 0.2% CPU", - "details": { - "duration": 10.0273277759552, - "points_saved": 0, - "points_rate": 0.0, - "variables_saved": 0, - "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.0, - "csv_write_time_avg": 0.0 - } - }, - { - "timestamp": "2025-08-18T18:08:38.436442", - "level": "info", - "event_type": "performance_report", - "message": "Performance report: 0 points saved, 0 lost, 0.2% CPU", - "details": { - "duration": 10.028436183929443, - "points_saved": 0, - "points_rate": 0.0, - "variables_saved": 0, - "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.0, - "csv_write_time_avg": 0.0 - } - }, - { - "timestamp": "2025-08-18T18:08:48.465434", - "level": "info", - "event_type": "performance_report", - "message": "Performance report: 0 points saved, 0 lost, 0.2% CPU", - "details": { - "duration": 10.028992652893066, - "points_saved": 0, - "points_rate": 0.0, - "variables_saved": 0, - "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.0, - "csv_write_time_avg": 0.0 - } - }, - { - "timestamp": "2025-08-18T18:08:58.494004", - "level": "info", - "event_type": "performance_report", - "message": "Performance report: 0 points saved, 0 lost, 0.2% CPU", - "details": { - "duration": 10.02856969833374, - "points_saved": 0, - "points_rate": 0.0, - "variables_saved": 0, - "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.0, - "csv_write_time_avg": 0.0 - } - }, - { - "timestamp": "2025-08-18T18:09:08.522456", - "level": "info", - "event_type": "performance_report", - "message": "Performance report: 0 points saved, 0 lost, 0.2% CPU", - "details": { - "duration": 10.028452157974243, - "points_saved": 0, - "points_rate": 0.0, - "variables_saved": 0, - "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.0, - "csv_write_time_avg": 0.0 - } - }, - { - "timestamp": "2025-08-18T18:09:18.553453", - "level": "info", - "event_type": "performance_report", - "message": "Performance report: 0 points saved, 0 lost, 0.2% CPU", - "details": { - "duration": 10.030997276306152, - "points_saved": 0, - "points_rate": 0.0, - "variables_saved": 0, - "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.0, - "csv_write_time_avg": 0.0 - } - }, - { - "timestamp": "2025-08-18T18:09:28.586171", - "level": "info", - "event_type": "performance_report", - "message": "Performance report: 0 points saved, 0 lost, 0.0% CPU", - "details": { - "duration": 10.032717227935791, - "points_saved": 0, - "points_rate": 0.0, - "variables_saved": 0, - "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.0, - "csv_write_time_avg": 0.0 - } - }, - { - "timestamp": "2025-08-18T18:09:38.617422", - "level": "info", - "event_type": "performance_report", - "message": "Performance report: 0 points saved, 0 lost, 0.0% CPU", - "details": { - "duration": 10.031250953674316, - "points_saved": 0, - "points_rate": 0.0, - "variables_saved": 0, - "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.0, - "csv_write_time_avg": 0.0 - } - }, - { - "timestamp": "2025-08-18T18:09:48.645742", - "level": "info", - "event_type": "performance_report", - "message": "Performance report: 0 points saved, 0 lost, 0.2% CPU", - "details": { - "duration": 10.0283203125, - "points_saved": 0, - "points_rate": 0.0, - "variables_saved": 0, - "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.0, - "csv_write_time_avg": 0.0 - } - }, - { - "timestamp": "2025-08-18T18:09:58.682568", - "level": "info", - "event_type": "performance_report", - "message": "Performance report: 0 points saved, 0 lost, 0.2% CPU", - "details": { - "duration": 10.03682565689087, - "points_saved": 0, - "points_rate": 0.0, - "variables_saved": 0, - "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.0, - "csv_write_time_avg": 0.0 - } - }, - { - "timestamp": "2025-08-18T18:10:08.714392", - "level": "info", - "event_type": "performance_report", - "message": "Performance report: 0 points saved, 0 lost, 0.2% CPU", - "details": { - "duration": 10.031824350357056, - "points_saved": 0, - "points_rate": 0.0, - "variables_saved": 0, - "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.0, - "csv_write_time_avg": 0.0 - } - }, - { - "timestamp": "2025-08-18T18:10:18.742293", - "level": "info", - "event_type": "performance_report", - "message": "Performance report: 0 points saved, 0 lost, 0.3% CPU", - "details": { - "duration": 10.02790117263794, - "points_saved": 0, - "points_rate": 0.0, - "variables_saved": 0, - "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.0, - "csv_write_time_avg": 0.0 - } - }, - { - "timestamp": "2025-08-18T18:10:28.777632", - "level": "info", - "event_type": "performance_report", - "message": "Performance report: 0 points saved, 0 lost, 0.0% CPU", - "details": { - "duration": 10.035338640213013, - "points_saved": 0, - "points_rate": 0.0, - "variables_saved": 0, - "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.0, - "csv_write_time_avg": 0.0 - } - }, - { - "timestamp": "2025-08-18T18:10:38.808102", - "level": "info", - "event_type": "performance_report", - "message": "Performance report: 0 points saved, 0 lost, 0.3% CPU", - "details": { - "duration": 10.030470371246338, - "points_saved": 0, - "points_rate": 0.0, - "variables_saved": 0, - "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.0, - "csv_write_time_avg": 0.0 - } - }, - { - "timestamp": "2025-08-18T18:10:48.839668", - "level": "info", - "event_type": "performance_report", - "message": "Performance report: 0 points saved, 0 lost, 0.0% CPU", - "details": { - "duration": 10.031565427780151, - "points_saved": 0, - "points_rate": 0.0, - "variables_saved": 0, - "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.0, - "csv_write_time_avg": 0.0 - } - }, - { - "timestamp": "2025-08-18T18:10:58.875359", - "level": "info", - "event_type": "performance_report", - "message": "Performance report: 0 points saved, 0 lost, 0.0% CPU", - "details": { - "duration": 10.035691976547241, - "points_saved": 0, - "points_rate": 0.0, - "variables_saved": 0, - "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.0, - "csv_write_time_avg": 0.0 - } - }, - { - "timestamp": "2025-08-18T18:11:08.904142", - "level": "info", - "event_type": "performance_report", - "message": "Performance report: 0 points saved, 0 lost, 0.3% CPU", - "details": { - "duration": 10.02878212928772, - "points_saved": 0, - "points_rate": 0.0, - "variables_saved": 0, - "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.0, - "csv_write_time_avg": 0.0 - } - }, - { - "timestamp": "2025-08-18T18:11:18.930315", - "level": "info", - "event_type": "performance_report", - "message": "Performance report: 0 points saved, 0 lost, 0.2% CPU", - "details": { - "duration": 10.026172876358032, - "points_saved": 0, - "points_rate": 0.0, - "variables_saved": 0, - "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.0, - "csv_write_time_avg": 0.0 - } - }, - { - "timestamp": "2025-08-18T18:11:28.963991", - "level": "info", - "event_type": "performance_report", - "message": "Performance report: 0 points saved, 0 lost, 0.2% CPU", - "details": { - "duration": 10.033675909042358, - "points_saved": 0, - "points_rate": 0.0, - "variables_saved": 0, - "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.0, - "csv_write_time_avg": 0.0 - } - }, - { - "timestamp": "2025-08-18T18:11:38.993825", - "level": "info", - "event_type": "performance_report", - "message": "Performance report: 0 points saved, 0 lost, 0.2% CPU", - "details": { - "duration": 10.029834747314453, - "points_saved": 0, - "points_rate": 0.0, - "variables_saved": 0, - "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.0, - "csv_write_time_avg": 0.0 - } - }, - { - "timestamp": "2025-08-18T18:11:49.024836", - "level": "info", - "event_type": "performance_report", - "message": "Performance report: 0 points saved, 0 lost, 0.2% CPU", - "details": { - "duration": 10.031010389328003, - "points_saved": 0, - "points_rate": 0.0, - "variables_saved": 0, - "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.0, - "csv_write_time_avg": 0.0 - } - }, - { - "timestamp": "2025-08-18T18:11:59.066613", - "level": "info", - "event_type": "performance_report", - "message": "Performance report: 0 points saved, 0 lost, 0.3% CPU", - "details": { - "duration": 10.041777610778809, - "points_saved": 0, - "points_rate": 0.0, - "variables_saved": 0, - "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.0, - "csv_write_time_avg": 0.0 - } - }, - { - "timestamp": "2025-08-18T18:12:09.095814", - "level": "info", - "event_type": "performance_report", - "message": "Performance report: 0 points saved, 0 lost, 0.0% CPU", - "details": { - "duration": 10.029201030731201, - "points_saved": 0, - "points_rate": 0.0, - "variables_saved": 0, - "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.0, - "csv_write_time_avg": 0.0 - } - }, - { - "timestamp": "2025-08-18T18:12:19.127242", - "level": "info", - "event_type": "performance_report", - "message": "Performance report: 0 points saved, 0 lost, 0.0% CPU", - "details": { - "duration": 10.03142762184143, - "points_saved": 0, - "points_rate": 0.0, - "variables_saved": 0, - "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.0, - "csv_write_time_avg": 0.0 - } - }, - { - "timestamp": "2025-08-18T18:12:29.156430", - "level": "info", - "event_type": "performance_report", - "message": "Performance report: 0 points saved, 0 lost, 0.0% CPU", - "details": { - "duration": 10.02918815612793, - "points_saved": 0, - "points_rate": 0.0, - "variables_saved": 0, - "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.0, - "csv_write_time_avg": 0.0 - } - }, - { - "timestamp": "2025-08-18T18:12:39.201669", - "level": "info", - "event_type": "performance_report", - "message": "Performance report: 0 points saved, 0 lost, 0.0% CPU", - "details": { - "duration": 10.045239210128784, - "points_saved": 0, - "points_rate": 0.0, - "variables_saved": 0, - "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.0, - "csv_write_time_avg": 0.0 - } - }, { "timestamp": "2025-08-18T18:12:49.231396", "level": "info", @@ -19518,8 +18368,1009 @@ "read_time_avg": 0.0936047391193669, "csv_write_time_avg": 1.2368690676805449e-05 } + }, + { + "timestamp": "2025-08-22T14:55:15.538114", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 40 points saved, 0 lost, 0.0% CPU", + "details": { + "duration": 10.028107404708862, + "points_saved": 40, + "points_rate": 3.988788550591046, + "variables_saved": 120, + "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.09516998529434204, + "csv_write_time_avg": 0.0 + } + }, + { + "timestamp": "2025-08-22T14:55:25.563066", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 40 points saved, 0 lost, 0.6% CPU", + "details": { + "duration": 10.024951934814453, + "points_saved": 40, + "points_rate": 3.9900440680507203, + "variables_saved": 120, + "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.09397122859954835, + "csv_write_time_avg": 0.0 + } + }, + { + "timestamp": "2025-08-22T14:55:35.584291", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 40 points saved, 0 lost, 0.2% CPU", + "details": { + "duration": 10.021225452423096, + "points_saved": 40, + "points_rate": 3.991527801655051, + "variables_saved": 120, + "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.09901020526885987, + "csv_write_time_avg": 0.0 + } + }, + { + "timestamp": "2025-08-22T14:55:45.605899", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 40 points saved, 0 lost, 0.0% CPU", + "details": { + "duration": 10.021607875823975, + "points_saved": 40, + "points_rate": 3.991375485414431, + "variables_saved": 120, + "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.0984384536743164, + "csv_write_time_avg": 0.0 + } + }, + { + "timestamp": "2025-08-22T14:55:55.629239", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 40 points saved, 0 lost, 0.2% CPU", + "details": { + "duration": 10.022833824157715, + "points_saved": 40, + "points_rate": 3.9908872781657103, + "variables_saved": 120, + "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.09964434504508972, + "csv_write_time_avg": 0.0 + } + }, + { + "timestamp": "2025-08-22T14:56:05.654436", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 40 points saved, 0 lost, 0.0% CPU", + "details": { + "duration": 10.025702714920044, + "points_saved": 40, + "points_rate": 3.9897452714683856, + "variables_saved": 120, + "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.10145392417907714, + "csv_write_time_avg": 0.0 + } + }, + { + "timestamp": "2025-08-22T14:56:15.680722", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 41 points saved, 0 lost, 0.2% CPU", + "details": { + "duration": 10.026286363601685, + "points_saved": 41, + "points_rate": 4.089250846538938, + "variables_saved": 123, + "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.09597469539177127, + "csv_write_time_avg": 0.0 + } + }, + { + "timestamp": "2025-08-22T14:56:25.720300", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 40 points saved, 0 lost, 0.0% CPU", + "details": { + "duration": 10.039578199386597, + "points_saved": 40, + "points_rate": 3.9842311305911178, + "variables_saved": 120, + "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.094185209274292, + "csv_write_time_avg": 0.0 + } + }, + { + "timestamp": "2025-08-22T14:56:35.743064", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 40 points saved, 0 lost, 0.0% CPU", + "details": { + "duration": 10.022167682647705, + "points_saved": 40, + "points_rate": 3.991152539710112, + "variables_saved": 120, + "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.09389466047286987, + "csv_write_time_avg": 0.0 + } + }, + { + "timestamp": "2025-08-22T14:56:45.769731", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 40 points saved, 0 lost, 0.0% CPU", + "details": { + "duration": 10.027262687683105, + "points_saved": 40, + "points_rate": 3.989124574260294, + "variables_saved": 120, + "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.0961844801902771, + "csv_write_time_avg": 0.0 + } + }, + { + "timestamp": "2025-08-22T14:56:55.799246", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 40 points saved, 0 lost, 0.2% CPU", + "details": { + "duration": 10.028987646102905, + "points_saved": 40, + "points_rate": 3.988438455754138, + "variables_saved": 120, + "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.12860987186431885, + "csv_write_time_avg": 0.0 + } + }, + { + "timestamp": "2025-08-22T14:57:05.829887", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 40 points saved, 0 lost, 0.3% CPU", + "details": { + "duration": 10.031168222427368, + "points_saved": 40, + "points_rate": 3.9875714486144562, + "variables_saved": 120, + "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.11599408388137818, + "csv_write_time_avg": 0.0 + } + }, + { + "timestamp": "2025-08-22T14:57:15.863559", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 40 points saved, 0 lost, 0.3% CPU", + "details": { + "duration": 10.032653570175171, + "points_saved": 40, + "points_rate": 3.986981083340805, + "variables_saved": 120, + "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.11252739429473876, + "csv_write_time_avg": 0.0 + } + }, + { + "timestamp": "2025-08-22T14:57:25.898973", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 40 points saved, 0 lost, 2.6% CPU", + "details": { + "duration": 10.036432981491089, + "points_saved": 40, + "points_rate": 3.9854797091523344, + "variables_saved": 120, + "udp_points_sent": 0, + "points_lost": 0, + "cpu_average": 2.6, + "cpu_max": 2.6, + "delay_average": 0.0, + "delay_max": 0.0, + "read_errors": 0, + "csv_errors": 0, + "udp_errors": 0, + "read_time_avg": 0.11626908779144288, + "csv_write_time_avg": 0.0 + } + }, + { + "timestamp": "2025-08-22T14:57:35.935361", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 40 points saved, 0 lost, 0.6% CPU", + "details": { + "duration": 10.03638768196106, + "points_saved": 40, + "points_rate": 3.98549769773184, + "variables_saved": 120, + "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.1162803590297699, + "csv_write_time_avg": 0.0 + } + }, + { + "timestamp": "2025-08-22T14:57:45.961635", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 40 points saved, 0 lost, 0.6% CPU", + "details": { + "duration": 10.02627420425415, + "points_saved": 40, + "points_rate": 3.989517859288946, + "variables_saved": 120, + "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.12955097556114198, + "csv_write_time_avg": 0.0 + } + }, + { + "timestamp": "2025-08-22T14:57:55.992792", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 40 points saved, 0 lost, 0.6% CPU", + "details": { + "duration": 10.030156373977661, + "points_saved": 40, + "points_rate": 3.987973717316751, + "variables_saved": 120, + "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.14729697108268738, + "csv_write_time_avg": 0.0 + } + }, + { + "timestamp": "2025-08-22T14:58:06.206848", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 40 points saved, 0 lost, 2.4% CPU", + "details": { + "duration": 10.215056657791138, + "points_saved": 40, + "points_rate": 3.91578836417824, + "variables_saved": 120, + "udp_points_sent": 0, + "points_lost": 0, + "cpu_average": 2.4, + "cpu_max": 2.4, + "delay_average": 0.0, + "delay_max": 0.0, + "read_errors": 0, + "csv_errors": 0, + "udp_errors": 0, + "read_time_avg": 0.10414276123046876, + "csv_write_time_avg": 0.0 + } + }, + { + "timestamp": "2025-08-22T14:58:16.252912", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 40 points saved, 0 lost, 0.8% CPU", + "details": { + "duration": 10.046063661575317, + "points_saved": 40, + "points_rate": 3.981659020636509, + "variables_saved": 120, + "udp_points_sent": 0, + "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.10142437815666198, + "csv_write_time_avg": 0.0 + } + }, + { + "timestamp": "2025-08-22T14:58:26.279205", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 41 points saved, 0 lost, 0.3% CPU", + "details": { + "duration": 10.025732278823853, + "points_saved": 41, + "points_rate": 4.089476844160238, + "variables_saved": 123, + "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.10207103519904905, + "csv_write_time_avg": 0.0 + } + }, + { + "timestamp": "2025-08-22T14:58:36.306372", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 39 points saved, 0 lost, 0.0% CPU", + "details": { + "duration": 10.027727842330933, + "points_saved": 39, + "points_rate": 3.889216043076664, + "variables_saved": 117, + "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.10139847413087502, + "csv_write_time_avg": 0.0 + } + }, + { + "timestamp": "2025-08-22T14:58:46.332190", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 42 points saved, 0 lost, 0.2% CPU", + "details": { + "duration": 10.02581787109375, + "points_saved": 42, + "points_rate": 4.189184417671661, + "variables_saved": 126, + "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.10499780518668038, + "csv_write_time_avg": 0.0 + } + }, + { + "timestamp": "2025-08-22T14:58:56.353238", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 40 points saved, 0 lost, 0.3% CPU", + "details": { + "duration": 10.021048545837402, + "points_saved": 40, + "points_rate": 3.991598266093164, + "variables_saved": 120, + "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.10673828125, + "csv_write_time_avg": 0.0 + } + }, + { + "timestamp": "2025-08-22T14:59:06.375347", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 40 points saved, 0 lost, 0.0% CPU", + "details": { + "duration": 10.021602869033813, + "points_saved": 40, + "points_rate": 3.991377479504575, + "variables_saved": 120, + "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.10858465433120727, + "csv_write_time_avg": 0.0 + } + }, + { + "timestamp": "2025-08-22T14:59:16.398012", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 40 points saved, 0 lost, 0.2% CPU", + "details": { + "duration": 10.023170471191406, + "points_saved": 40, + "points_rate": 3.9907532367096805, + "variables_saved": 120, + "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.10688149333000183, + "csv_write_time_avg": 0.0 + } + }, + { + "timestamp": "2025-08-22T14:59:26.423918", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 40 points saved, 0 lost, 0.0% CPU", + "details": { + "duration": 10.025906324386597, + "points_saved": 40, + "points_rate": 3.989664246383957, + "variables_saved": 120, + "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.11542494893074036, + "csv_write_time_avg": 0.0 + } + }, + { + "timestamp": "2025-08-22T14:59:36.453416", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 40 points saved, 0 lost, 0.3% CPU", + "details": { + "duration": 10.029498100280762, + "points_saved": 40, + "points_rate": 3.988235463036805, + "variables_saved": 120, + "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.10728968381881714, + "csv_write_time_avg": 0.0 + } + }, + { + "timestamp": "2025-08-22T14:59:46.475162", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 40 points saved, 0 lost, 0.5% CPU", + "details": { + "duration": 10.021745443344116, + "points_saved": 40, + "points_rate": 3.9913206961932732, + "variables_saved": 120, + "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.10595067739486694, + "csv_write_time_avg": 0.0 + } + }, + { + "timestamp": "2025-08-22T14:59:56.496770", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 40 points saved, 0 lost, 0.3% CPU", + "details": { + "duration": 10.021055936813354, + "points_saved": 40, + "points_rate": 3.9915953221113143, + "variables_saved": 120, + "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.10959045886993408, + "csv_write_time_avg": 0.0 + } + }, + { + "timestamp": "2025-08-22T15:00:06.518683", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 40 points saved, 0 lost, 0.2% CPU", + "details": { + "duration": 10.022464990615845, + "points_saved": 40, + "points_rate": 3.991034145537299, + "variables_saved": 120, + "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.10856413841247559, + "csv_write_time_avg": 0.0 + } + }, + { + "timestamp": "2025-08-22T15:00:15.551514", + "level": "info", + "event_type": "udp_streaming_stopped", + "message": "UDP streaming to PlotJuggler stopped (CSV recording continues)", + "details": {} + }, + { + "timestamp": "2025-08-22T15:00:16.540372", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 40 points saved, 0 lost, 0.2% CPU", + "details": { + "duration": 10.021689891815186, + "points_saved": 40, + "points_rate": 3.9913428206023815, + "variables_saved": 120, + "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.10616881847381592, + "csv_write_time_avg": 0.0 + } + }, + { + "timestamp": "2025-08-22T15:00:22.484694", + "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-22T15:00:22.505183", + "level": "info", + "event_type": "udp_streaming_stopped", + "message": "UDP streaming to PlotJuggler stopped (CSV recording continues)", + "details": {} + }, + { + "timestamp": "2025-08-22T15:00:22.834644", + "level": "info", + "event_type": "dataset_deactivated", + "message": "Dataset deactivated: DAR", + "details": { + "dataset_id": "DAR" + } + }, + { + "timestamp": "2025-08-22T15:00:23.257309", + "level": "info", + "event_type": "dataset_deactivated", + "message": "Dataset deactivated: Fast", + "details": { + "dataset_id": "Fast" + } + }, + { + "timestamp": "2025-08-22T15:00:23.279651", + "level": "info", + "event_type": "dataset_deactivated", + "message": "Dataset deactivated: test", + "details": { + "dataset_id": "Test" + } + }, + { + "timestamp": "2025-08-22T15:00:23.306757", + "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-22T15:01:09.434052", + "level": "info", + "event_type": "application_started", + "message": "Application initialization completed successfully", + "details": {} + }, + { + "timestamp": "2025-08-22T15:01:09.543154", + "level": "info", + "event_type": "dataset_activated", + "message": "Dataset activated: DAR", + "details": { + "dataset_id": "DAR", + "variables_count": 3, + "streaming_count": 3, + "prefix": "gateway_phoenix" + } + }, + { + "timestamp": "2025-08-22T15:01:09.565154", + "level": "info", + "event_type": "dataset_activated", + "message": "Dataset activated: Fast", + "details": { + "dataset_id": "Fast", + "variables_count": 3, + "streaming_count": 1, + "prefix": "fast" + } + }, + { + "timestamp": "2025-08-22T15:01:09.587453", + "level": "info", + "event_type": "csv_recording_started", + "message": "๐Ÿ”ฅ CRITICAL PRIORITY: CSV recording started with MAXIMUM PRIORITY, async buffering, and performance monitoring: 2 datasets activated", + "details": { + "activated_datasets": 2, + "total_datasets": 3, + "priority": "CRITICAL", + "recording_protection": true, + "performance_monitoring": true, + "async_csv_buffering": true, + "csv_flush_interval": 5.0 + } + }, + { + "timestamp": "2025-08-22T15:01:19.543346", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 40 points saved, 0 lost, 0.0% CPU", + "details": { + "duration": 11.113290786743164, + "points_saved": 40, + "points_rate": 3.5992939236067905, + "variables_saved": 120, + "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.09103001952171326, + "csv_write_time_avg": 1.912713050842285e-05 + } + }, + { + "timestamp": "2025-08-22T15:01:29.566896", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 40 points saved, 0 lost, 1.7% CPU", + "details": { + "duration": 10.0229811668396, + "points_saved": 40, + "points_rate": 3.990828610188102, + "variables_saved": 120, + "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.09249638319015503, + "csv_write_time_avg": 2.7358531951904296e-06 + } + }, + { + "timestamp": "2025-08-22T15:01:39.589874", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 40 points saved, 0 lost, 0.5% CPU", + "details": { + "duration": 10.023546695709229, + "points_saved": 40, + "points_rate": 3.9906034474925693, + "variables_saved": 120, + "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.08856287002563476, + "csv_write_time_avg": 2.652406692504883e-06 + } + }, + { + "timestamp": "2025-08-22T15:01:49.618876", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 40 points saved, 0 lost, 0.5% CPU", + "details": { + "duration": 10.029001951217651, + "points_saved": 40, + "points_rate": 3.988432766746394, + "variables_saved": 120, + "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.0887589156627655, + "csv_write_time_avg": 7.718801498413086e-06 + } + }, + { + "timestamp": "2025-08-22T15:01:59.644350", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 41 points saved, 0 lost, 0.3% CPU", + "details": { + "duration": 10.02537488937378, + "points_saved": 41, + "points_rate": 4.089622627823847, + "variables_saved": 123, + "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.09120483514739246, + "csv_write_time_avg": 8.338835181259528e-06 + } + }, + { + "timestamp": "2025-08-22T15:02:09.672017", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 40 points saved, 0 lost, 0.5% CPU", + "details": { + "duration": 10.027766466140747, + "points_saved": 40, + "points_rate": 3.9889241672172955, + "variables_saved": 120, + "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.09168168306350707, + "csv_write_time_avg": 7.5161457061767575e-06 + } + }, + { + "timestamp": "2025-08-22T15:02:19.698893", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 40 points saved, 0 lost, 0.8% CPU", + "details": { + "duration": 10.026078462600708, + "points_saved": 40, + "points_rate": 3.989595747650296, + "variables_saved": 120, + "udp_points_sent": 0, + "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.09049486517906188, + "csv_write_time_avg": 1.6683340072631835e-05 + } + }, + { + "timestamp": "2025-08-22T15:02:29.723080", + "level": "info", + "event_type": "performance_report", + "message": "Performance report: 40 points saved, 0 lost, 0.6% CPU", + "details": { + "duration": 10.024984121322632, + "points_saved": 40, + "points_rate": 3.990031257498157, + "variables_saved": 120, + "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.09210201501846313, + "csv_write_time_avg": 5.84721565246582e-06 + } } ], - "last_updated": "2025-08-22T14:55:05.510552", + "last_updated": "2025-08-22T15:02:29.723080", "total_entries": 1000 } \ No newline at end of file diff --git a/backend_manager.status b/backend_manager.status index 01ad11c..12dd826 100644 --- a/backend_manager.status +++ b/backend_manager.status @@ -1,9 +1,9 @@ { - "timestamp": "2025-08-22T14:55:09.660532", - "status": "healthy", + "timestamp": "2025-08-22T15:14:03.883875", + "status": "stopped", "restart_count": 0, "last_restart": 0, - "backend_pid": 33120, - "manager_pid": 1488, + "backend_pid": 33676, + "manager_pid": 25004, "details": {} } \ No newline at end of file diff --git a/backmanager.py b/backmanager.py index cef8712..5564e82 100644 --- a/backmanager.py +++ b/backmanager.py @@ -27,16 +27,18 @@ from typing import Optional, Dict, Any class BackendManager: """Manages backend lifecycle and health monitoring""" - - def __init__(self, - check_interval: int = 30, - health_timeout: float = 5.0, - restart_delay: int = 10, - max_restart_attempts: int = 3, - restart_cooldown: int = 300): + + def __init__( + self, + check_interval: int = 30, + health_timeout: float = 5.0, + restart_delay: int = 10, + max_restart_attempts: int = 3, + restart_cooldown: int = 300, + ): """ Initialize the backend manager - + Args: check_interval: Health check interval in seconds (default: 30) health_timeout: HTTP request timeout in seconds (default: 5.0) @@ -49,50 +51,52 @@ class BackendManager: self.restart_delay = restart_delay self.max_restart_attempts = max_restart_attempts self.restart_cooldown = restart_cooldown - + # Configuration self.backend_port = 5050 self.health_endpoint = "/api/health" self.base_url = f"http://localhost:{self.backend_port}" self.lock_file = "plc_streamer.lock" self.status_file = "backend_manager.status" - + # State tracking self.restart_count = 0 self.last_restart_time = 0 self.backend_process = None self.running = True - + # Setup logging self.setup_logging() - + # Detect environment - self.is_packaged = getattr(sys, 'frozen', False) - + self.is_packaged = getattr(sys, "frozen", False) + self.log(f"[MAIN] Backend Manager initialized") self.log(f"[CONFIG] Check interval: {check_interval}s") - self.log(f"[CONFIG] Environment: {'Packaged' if self.is_packaged else 'Development'}") + self.log( + f"[CONFIG] Environment: {'Packaged' if self.is_packaged else 'Development'}" + ) self.log(f"[CONFIG] Process separation: Independent cmd windows") - + def setup_logging(self): """Setup logging configuration""" - log_format = '%(asctime)s [%(levelname)s] %(message)s' - + log_format = "%(asctime)s [%(levelname)s] %(message)s" + # Configure file handler with UTF-8 encoding - file_handler = logging.FileHandler('backend_manager.log', encoding='utf-8') + file_handler = logging.FileHandler("backend_manager.log", encoding="utf-8") file_handler.setFormatter(logging.Formatter(log_format)) - + # Configure console handler with UTF-8 encoding console_handler = logging.StreamHandler(sys.stdout) console_handler.setFormatter(logging.Formatter(log_format)) - + logging.basicConfig( level=logging.INFO, format=log_format, - handlers=[file_handler, console_handler] + handlers=[file_handler, console_handler], ) self.logger = logging.getLogger(__name__) - + def log(self, message: str, level: str = "INFO"): """Log message with appropriate level""" if level == "ERROR": @@ -101,12 +105,14 @@ class BackendManager: self.logger.warning(message) else: self.logger.info(message) - + def get_backend_command(self) -> list: """Get the appropriate backend command for current environment (legacy - kept for compatibility)""" if self.is_packaged: # In packaged environment, look for the exe - exe_path = os.path.join(os.path.dirname(sys.executable), "S7_Streamer_Logger.exe") + exe_path = os.path.join( + os.path.dirname(sys.executable), "S7_Streamer_Logger.exe" + ) if os.path.exists(exe_path): return [exe_path] else: @@ -125,56 +131,59 @@ class BackendManager: python_exe = sys.executable main_script = os.path.join(os.path.dirname(__file__), "main.py") return [python_exe, main_script] - + def is_backend_alive(self) -> bool: """Check if backend is responding to health checks""" try: response = requests.get( - f"{self.base_url}{self.health_endpoint}", - timeout=self.health_timeout + f"{self.base_url}{self.health_endpoint}", timeout=self.health_timeout ) return 200 <= response.status_code < 300 - except (requests.RequestException, requests.ConnectionError, - requests.Timeout, requests.ConnectTimeout): + except ( + requests.RequestException, + requests.ConnectionError, + requests.Timeout, + requests.ConnectTimeout, + ): return False except Exception as e: self.log(f"[ERROR] Unexpected error during health check: {e}", "ERROR") return False - + def get_backend_pid(self) -> Optional[int]: """Get backend PID from lock file""" try: if os.path.exists(self.lock_file): - with open(self.lock_file, 'r') as f: + with open(self.lock_file, "r") as f: return int(f.read().strip()) except (ValueError, FileNotFoundError, IOError): pass return None - + def is_backend_process_running(self, pid: int) -> bool: """Check if backend process is actually running""" try: if not psutil.pid_exists(pid): return False - + proc = psutil.Process(pid) cmdline = " ".join(proc.cmdline()).lower() - + # Check for backend signatures signatures = ["main.py", "s7_streamer_logger", "plc_streamer"] return any(sig in cmdline for sig in signatures) except (psutil.NoSuchProcess, psutil.AccessDenied, psutil.ZombieProcess): return False - + def cleanup_zombie_process(self, pid: int) -> bool: """Terminate zombie backend process""" try: if not psutil.pid_exists(pid): return True - + proc = psutil.Process(pid) self.log(f"[STOP] Terminating zombie process {pid} ({proc.name()})") - + # Try graceful termination proc.terminate() try: @@ -188,13 +197,13 @@ class BackendManager: proc.wait(timeout=5) self.log(f"[KILL] Process {pid} force killed") return True - + except (psutil.NoSuchProcess, psutil.AccessDenied): return True except Exception as e: self.log(f"[ERROR] Error terminating process {pid}: {e}", "ERROR") return False - + def cleanup_lock_file(self): """Remove stale lock file""" try: @@ -203,12 +212,14 @@ class BackendManager: self.log(f"[OK] Removed lock file: {self.lock_file}") except Exception as e: self.log(f"[ERROR] Error removing lock file: {e}", "ERROR") - + def get_cmd_command(self) -> str: """Get Windows cmd command to launch backend in separate console window""" if self.is_packaged: # In packaged environment, launch exe in new cmd window - exe_path = os.path.join(os.path.dirname(sys.executable), "S7_Streamer_Logger.exe") + exe_path = os.path.join( + os.path.dirname(sys.executable), "S7_Streamer_Logger.exe" + ) if os.path.exists(exe_path): return f'start "S7_Streamer_Logger" "{exe_path}"' else: @@ -225,74 +236,86 @@ class BackendManager: python_exe = sys.executable main_script = os.path.join(os.path.dirname(__file__), "main.py") return f'start "PLC_Backend" "{python_exe}" "{main_script}"' - + def start_backend(self) -> bool: """Start the backend process in a separate Windows cmd console""" try: cmd_command = self.get_cmd_command() self.log(f"[START] Starting backend in separate cmd window: {cmd_command}") - + # Launch backend in completely separate cmd window using shell command self.backend_process = subprocess.Popen( cmd_command, cwd=os.path.dirname(__file__) if not self.is_packaged else None, - shell=True # Use shell to properly handle the start command + shell=True, # Use shell to properly handle the start command ) - - self.log(f"[START] Backend launch command executed with PID: {self.backend_process.pid}") - + + self.log( + f"[START] Backend launch command executed with PID: {self.backend_process.pid}" + ) + # Wait a moment for the actual backend to start in its new window - self.log(f"[WAIT] Waiting 10 seconds for backend to initialize in separate window...") + self.log( + f"[WAIT] Waiting 10 seconds for backend to initialize in separate window..." + ) time.sleep(10) - + # The subprocess.Popen PID is just the cmd launcher, not the actual backend # We'll verify health via HTTP instead of process tracking self.log(f"[OK] Backend launch completed, will verify via health check") return True - + except Exception as e: self.log(f"[ERROR] Error starting backend: {e}", "ERROR") return False - + def handle_backend_failure(self) -> bool: """Handle backend failure and attempt restart""" current_time = time.time() - + # Check if we're in cooldown period if (current_time - self.last_restart_time) < self.restart_cooldown: time_left = self.restart_cooldown - (current_time - self.last_restart_time) self.log(f"[WAIT] In cooldown period, {int(time_left)}s remaining") return False - + # Check restart attempt limit if self.restart_count >= self.max_restart_attempts: - self.log(f"[FAIL] Maximum restart attempts ({self.max_restart_attempts}) reached") + self.log( + f"[FAIL] Maximum restart attempts ({self.max_restart_attempts}) reached" + ) self.restart_count = 0 self.last_restart_time = current_time return False - + # Cleanup existing processes backend_pid = self.get_backend_pid() if backend_pid and self.is_backend_process_running(backend_pid): self.log(f"[STOP] Cleaning up zombie backend process: {backend_pid}") self.cleanup_zombie_process(backend_pid) - + self.cleanup_lock_file() - + # Wait before restart - self.log(f"[WAIT] Waiting {self.restart_delay}s before restart attempt {self.restart_count + 1}") + self.log( + f"[WAIT] Waiting {self.restart_delay}s before restart attempt {self.restart_count + 1}" + ) time.sleep(self.restart_delay) - + # Attempt restart self.restart_count += 1 if self.start_backend(): - self.log(f"[OK] Backend restarted successfully (attempt {self.restart_count})") + self.log( + f"[OK] Backend restarted successfully (attempt {self.restart_count})" + ) self.restart_count = 0 # Reset counter on success return True else: - self.log(f"[FAIL] Backend restart failed (attempt {self.restart_count})", "ERROR") + self.log( + f"[FAIL] Backend restart failed (attempt {self.restart_count})", "ERROR" + ) return False - + def update_status(self, status: str, details: Dict[str, Any] = None): """Update status file with current state""" try: @@ -303,40 +326,42 @@ class BackendManager: "last_restart": self.last_restart_time, "backend_pid": self.get_backend_pid(), "manager_pid": os.getpid(), - "details": details or {} + "details": details or {}, } - - with open(self.status_file, 'w') as f: + + with open(self.status_file, "w") as f: json.dump(status_data, f, indent=2) - + except Exception as e: self.log(f"[ERROR] Error updating status file: {e}", "ERROR") - + def run(self): """Main monitoring loop""" self.log(f"[START] Backend Manager started (PID: {os.getpid()})") self.update_status("starting") - + while self.running: try: # Check backend health if self.is_backend_alive(): self.log(f"[OK] Backend is healthy") self.update_status("healthy") - self.restart_count = 0 # Reset restart counter on successful health check + self.restart_count = ( + 0 # Reset restart counter on successful health check + ) else: self.log(f"[WARN] Backend health check failed", "WARN") self.update_status("unhealthy") - + # Attempt to handle the failure if self.handle_backend_failure(): self.update_status("restarted") else: self.update_status("failed") - + # Wait for next check time.sleep(self.check_interval) - + except KeyboardInterrupt: self.log(f"[SHUTDOWN] Received interrupt signal") self.running = False @@ -345,17 +370,19 @@ class BackendManager: self.log(f"[ERROR] Unexpected error in main loop: {e}", "ERROR") self.update_status("error", {"error": str(e)}) time.sleep(self.check_interval) - + self.shutdown() - + def shutdown(self): """Cleanup and shutdown""" self.log(f"[SHUTDOWN] Backend Manager shutting down") self.update_status("shutting_down") - + # Don't terminate any backend processes - they run independently in their own cmd windows # The manager only monitors health, doesn't control the backend lifecycle directly - self.log(f"[OK] Backend Manager stopped - backend continues running independently") + self.log( + f"[OK] Backend Manager stopped - backend continues running independently" + ) self.update_status("stopped") @@ -363,7 +390,7 @@ def main(): """Main entry point""" print("Backend Manager - PLC S7-315 Streamer Watchdog") print("=" * 50) - + try: manager = BackendManager() manager.run() @@ -372,7 +399,7 @@ def main(): except Exception as e: print(f"[ERROR] Critical error: {e}") return 1 - + return 0 diff --git a/core/rotating_logger.py b/core/rotating_logger.py index a659da9..f4dff02 100644 --- a/core/rotating_logger.py +++ b/core/rotating_logger.py @@ -76,7 +76,9 @@ class RotatingFileHandler(logging.Handler): oldest_file = log_files.pop(0) try: os.remove(oldest_file) - print(f"[CLEANUP] Removed old log file: {os.path.basename(oldest_file)}") + print( + f"[CLEANUP] Removed old log file: {os.path.basename(oldest_file)}" + ) except OSError as e: print(f"[WARNING] Could not remove {oldest_file}: {e}") diff --git a/main copy.spec b/main copy.spec new file mode 100644 index 0000000..da3daf9 --- /dev/null +++ b/main copy.spec @@ -0,0 +1,267 @@ +# -*- mode: python ; coding: utf-8 -*- +import os +import sys + +block_cipher = None + +# Analysis for main application (backend) +a_main = Analysis( + ['main.py'], + pathex=[], + binaries=[ + # Include snap7.dll - now confirmed to be in project root + ('snap7.dll', '.'), + ], + datas=[ + # Include the entire frontend build + ('frontend/dist', 'frontend/dist'), + + # Include configuration directories and schemas + ('config', 'config'), + + # Include core modules + ('core', 'core'), + + # Include utils + ('utils', 'utils'), + + # Include translation files + ('translation.json', '.'), + ('i18n.js', '.'), + + ], + hiddenimports=[ + # Flask and web dependencies + 'jinja2.ext', + 'flask', + 'flask_cors', + 'flask_socketio', + 'socketio', + 'werkzeug', + + # JSON Schema validation + 'jsonschema', + 'jsonschema.validators', + 'jsonschema._format', + 'jsonschema._types', + + # PLC and system dependencies + 'snap7', + 'psutil._pswindows', + 'psutil._psutil_windows', + + # Data processing + 'pandas', + 'numpy', + + # Threading and networking + 'threading', + 'socket', + 'json', + 'csv', + 'datetime', + 'pathlib', + + # Core modules (explicit imports) + 'core.config_manager', + 'core.plc_client', + 'core.plc_data_streamer', + 'core.event_logger', + 'core.instance_manager', + 'core.schema_manager', + 'core.streamer', + 'core.plot_manager', + 'core.historical_cache', + 'core.performance_monitor', + 'core.priority_manager', + 'core.rotating_logger', + + # Utils modules + 'utils.csv_validator', + 'utils.json_manager', + 'utils.symbol_loader', + 'utils.symbol_processor', + 'utils.instance_manager', + ], + hookspath=[], + hooksconfig={}, + runtime_hooks=[], + excludes=[ + # Exclude unnecessary packages to reduce size + 'matplotlib', + 'scipy', + 'IPython', + 'notebook', + 'jupyter', + 'tests', + 'unittest', + 'pydoc', + 'doctest', + ], + win_no_prefer_redirects=False, + win_private_assemblies=False, + cipher=block_cipher, + noarchive=False, +) + +# Analysis for backend manager (watchdog) +a_manager = Analysis( + ['backmanager.py'], + pathex=[], + binaries=[], + datas=[ + # Include utils for instance management + ('utils', 'utils'), + ], + hiddenimports=[ + # System and monitoring dependencies + 'psutil', + 'psutil._pswindows', + 'psutil._psutil_windows', + 'requests', + 'subprocess', + 'logging', + 'json', + + # Utils modules needed by manager + 'utils.instance_manager', + ], + hookspath=[], + hooksconfig={}, + runtime_hooks=[], + excludes=[ + # Exclude heavy packages not needed by manager + 'matplotlib', + 'scipy', + 'IPython', + 'notebook', + 'jupyter', + 'flask', + 'snap7', + 'pandas', + 'numpy', + ], + win_no_prefer_redirects=False, + win_private_assemblies=False, + cipher=block_cipher, + noarchive=False, +) + +# Build PYZ files +pyz_main = PYZ(a_main.pure, a_main.zipped_data, cipher=block_cipher) +pyz_manager = PYZ(a_manager.pure, a_manager.zipped_data, cipher=block_cipher) + +# Build main backend executable +exe_main = EXE( + pyz_main, + a_main.scripts, + [], + exclude_binaries=True, + name='S7_Streamer_Logger', + debug=False, + bootloader_ignore_signals=False, + strip=False, + upx=True, + console=True, # True para ver los logs del servidor en una consola. + disable_windowed_traceback=False, + argv_emulation=False, + target_arch=None, + codesign_identity=None, + entitlements_file=None, +) + +# Build backend manager executable +exe_manager = EXE( + pyz_manager, + a_manager.scripts, + [], + exclude_binaries=True, + name='Backend_Manager', + debug=False, + bootloader_ignore_signals=False, + strip=False, + upx=True, + console=True, + disable_windowed_traceback=False, + argv_emulation=False, + target_arch=None, + codesign_identity=None, + entitlements_file=None, +) + +# Collect all files together - Only include executables and shared dependencies +coll = COLLECT( + exe_main, + exe_manager, + a_main.binaries, + a_main.zipfiles, + a_main.datas, + # Don't duplicate manager dependencies since they're minimal + strip=False, + upx=True, + upx_exclude=[], + name='main' +) + +# Post-build: Copy config directory to the same level as the executable +import shutil +import os + +def copy_config_external(): + """Copy config directory to external location for runtime access""" + try: + # Get absolute paths + current_dir = os.path.abspath('.') + source_config = os.path.join(current_dir, 'config') + dist_main_dir = os.path.join(current_dir, 'dist', 'main') + dest_config = os.path.join(dist_main_dir, 'config') + + print(f"Current directory: {current_dir}") + print(f"Source config: {source_config}") + print(f"Destination config: {dest_config}") + + # Ensure dist/main directory exists + os.makedirs(dist_main_dir, exist_ok=True) + + # Remove existing config if present + if os.path.exists(dest_config): + shutil.rmtree(dest_config) + print(f"Removed existing config at: {dest_config}") + + # Copy config directory to dist/main/config + if os.path.exists(source_config): + shutil.copytree(source_config, dest_config) + print(f"โœ“ Config directory copied to: {dest_config}") + return True + else: + print(f"โœ— Source config directory not found: {source_config}") + return False + + except Exception as e: + print(f"โœ— Error copying config directory: {e}") + return False + +# Execute the copy operation +copy_config_external() + +def config_path(relative_path): + """Get path to config file, checking external location first when running as executable""" + if getattr(sys, 'frozen', False): + # Running as executable - config should be at same level as executable + executable_dir = os.path.dirname(sys.executable) + external_config = os.path.join(executable_dir, 'config', relative_path) + + if os.path.exists(external_config): + return external_config + + # Fallback to internal config within _internal + internal_config = os.path.join(executable_dir, '_internal', 'config', relative_path) + if os.path.exists(internal_config): + return internal_config + + raise FileNotFoundError(f"Configuration file not found: {relative_path}") + else: + # Running as script - use standard path + base_dir = os.path.dirname(os.path.abspath(__file__)) + project_root = os.path.dirname(base_dir) + return os.path.join(project_root, 'config', relative_path) diff --git a/main.py b/main.py index ee042d6..793fa43 100644 --- a/main.py +++ b/main.py @@ -54,46 +54,48 @@ from utils.symbol_processor import SymbolProcessor from utils.instance_manager import InstanceManager -def check_backend_instance_robust(port: int = 5050, lock_file: str = "plc_streamer.lock"): +def check_backend_instance_robust( + port: int = 5050, lock_file: str = "plc_streamer.lock" +): """ ๐Ÿ”’ ROBUST INSTANCE CHECK - HTTP + PID based verification - + This function provides a more reliable way to detect existing backend instances: 1. Double HTTP health check with 5-second interval 2. PID verification and zombie process cleanup 3. Automatic lock file management - + Args: port: Backend server port (default: 5050) lock_file: Lock file path (default: "plc_streamer.lock") - + Returns: Tuple[bool, str]: (can_proceed, message) - can_proceed: True if this instance can start safely - message: Detailed status message """ print("๐Ÿ” Starting robust backend instance verification...") - + try: # Initialize instance manager instance_manager = InstanceManager(port=port, lock_file=lock_file) - + # Perform comprehensive instance check can_proceed, message = instance_manager.check_and_handle_existing_instance() - + if can_proceed: print(f"โœ… {message}") print("๐Ÿ”’ Initializing new backend instance...") - + # Create lock file for this instance if not instance_manager.initialize_instance(): return False, "โŒ Failed to create instance lock file" - + return True, "โœ… Backend instance ready to start" else: print(f"๐Ÿšซ {message}") return False, message - + except Exception as e: error_msg = f"โŒ Error during instance verification: {e}" print(error_msg) @@ -3234,6 +3236,7 @@ def graceful_shutdown(): # Fallback to direct file removal try: import os + lock_file = "plc_streamer.lock" if os.path.exists(lock_file): os.remove(lock_file) @@ -3950,10 +3953,12 @@ if __name__ == "__main__": print("=" * 60) can_proceed, check_message = check_backend_instance_robust(port=5050) print("=" * 60) - + if not can_proceed: print(f"โŒ Startup aborted: {check_message}") - print("๐Ÿ’ก Tip: If you believe this is an error, check Task Manager for python.exe processes") + print( + "๐Ÿ’ก Tip: If you believe this is an error, check Task Manager for python.exe processes" + ) # input("\nPress Enter to exit...") sys.exit(1) diff --git a/main.spec b/main.spec index 94142a7..cc0b04d 100644 --- a/main.spec +++ b/main.spec @@ -4,8 +4,8 @@ import sys block_cipher = None -# Analysis for main application (backend) -a_main = Analysis( +# Analysis for main application +a = Analysis( ['main.py'], pathex=[], binaries=[ @@ -81,7 +81,6 @@ a_main = Analysis( 'utils.json_manager', 'utils.symbol_loader', 'utils.symbol_processor', - 'utils.instance_manager', ], hookspath=[], hooksconfig={}, @@ -104,42 +103,38 @@ a_main = Analysis( noarchive=False, ) -# Analysis for backend manager (watchdog) +# Analysis for backend manager a_manager = Analysis( ['backmanager.py'], pathex=[], binaries=[], - datas=[ - # Include utils for instance management - ('utils', 'utils'), - ], + datas=[], hiddenimports=[ - # System and monitoring dependencies + # Backend manager dependencies 'psutil', 'psutil._pswindows', 'psutil._psutil_windows', 'requests', + 'json', + 'datetime', + 'threading', 'subprocess', 'logging', - 'json', - - # Utils modules needed by manager - 'utils.instance_manager', ], hookspath=[], hooksconfig={}, runtime_hooks=[], excludes=[ - # Exclude heavy packages not needed by manager + # Exclude unnecessary packages to reduce size 'matplotlib', 'scipy', 'IPython', 'notebook', 'jupyter', - 'flask', - 'snap7', - 'pandas', - 'numpy', + 'tests', + 'unittest', + 'pydoc', + 'doctest', ], win_no_prefer_redirects=False, win_private_assemblies=False, @@ -147,14 +142,12 @@ a_manager = Analysis( noarchive=False, ) -# Build PYZ files -pyz_main = PYZ(a_main.pure, a_main.zipped_data, cipher=block_cipher) +pyz = PYZ(a.pure, a.zipped_data, cipher=block_cipher) pyz_manager = PYZ(a_manager.pure, a_manager.zipped_data, cipher=block_cipher) -# Build main backend executable -exe_main = EXE( - pyz_main, - a_main.scripts, +exe = EXE( + pyz, + a.scripts, [], exclude_binaries=True, name='S7_Streamer_Logger', @@ -170,7 +163,7 @@ exe_main = EXE( entitlements_file=None, ) -# Build backend manager executable +# Executable for backend manager exe_manager = EXE( pyz_manager, a_manager.scripts, @@ -181,7 +174,7 @@ exe_manager = EXE( bootloader_ignore_signals=False, strip=False, upx=True, - console=True, + console=True, # True para ver los logs del manager en una consola. disable_windowed_traceback=False, argv_emulation=False, target_arch=None, @@ -189,10 +182,15 @@ exe_manager = EXE( entitlements_file=None, ) -# Collect all files together coll = COLLECT( - exe_main, a_main.binaries, a_main.zipfiles, a_main.datas, - exe_manager, a_manager.binaries, a_manager.zipfiles, a_manager.datas, + exe, + a.binaries, + a.zipfiles, + a.datas, + exe_manager, + a_manager.binaries, + a_manager.zipfiles, + a_manager.datas, strip=False, upx=True, upx_exclude=[], diff --git a/system_state.json b/system_state.json index 0011fb9..e512204 100644 --- a/system_state.json +++ b/system_state.json @@ -3,11 +3,11 @@ "should_connect": true, "should_stream": false, "active_datasets": [ - "DAR", "Fast", - "Test" + "Test", + "DAR" ] }, "auto_recovery_enabled": true, - "last_update": "2025-08-22T14:54:15.476402" + "last_update": "2025-08-22T15:01:09.609437" } \ No newline at end of file diff --git a/utils/instance_manager.py b/utils/instance_manager.py index c9b74a6..5718d77 100644 --- a/utils/instance_manager.py +++ b/utils/instance_manager.py @@ -24,16 +24,18 @@ from typing import Optional, Tuple class InstanceManager: """Manages backend instance lifecycle and prevents duplicate executions""" - - def __init__(self, - port: int = 5050, - lock_file: str = "plc_streamer.lock", - health_endpoint: str = "/api/health", - check_timeout: float = 3.0, - check_interval: float = 5.0): + + def __init__( + self, + port: int = 5050, + lock_file: str = "plc_streamer.lock", + health_endpoint: str = "/api/health", + check_timeout: float = 3.0, + check_interval: float = 5.0, + ): """ Initialize the instance manager - + Args: port: Backend server port to check lock_file: Path to the PID lock file @@ -47,99 +49,102 @@ class InstanceManager: self.check_timeout = check_timeout self.check_interval = check_interval self.base_url = f"http://localhost:{port}" - + def is_backend_alive_http(self) -> bool: """ Check if backend is alive via HTTP health check - + Returns: True if backend responds to health check, False otherwise """ try: response = requests.get( - f"{self.base_url}{self.health_endpoint}", - timeout=self.check_timeout + f"{self.base_url}{self.health_endpoint}", timeout=self.check_timeout ) # Accept any successful HTTP response (200-299) return 200 <= response.status_code < 300 - - except (requests.RequestException, requests.ConnectionError, - requests.Timeout, requests.ConnectTimeout): + + except ( + requests.RequestException, + requests.ConnectionError, + requests.Timeout, + requests.ConnectTimeout, + ): return False except Exception as e: print(f"โš ๏ธ Unexpected error during health check: {e}") return False - + def get_lock_file_pid(self) -> Optional[int]: """ Read PID from lock file - + Returns: PID if lock file exists and is valid, None otherwise """ if not os.path.exists(self.lock_file): return None - + try: with open(self.lock_file, "r") as f: content = f.read().strip() return int(content) if content else None except (ValueError, FileNotFoundError, IOError): return None - + def is_process_our_backend(self, pid: int) -> bool: """ Verify if the process with given PID is our backend application - + Args: pid: Process ID to check - + Returns: True if it's our backend process, False otherwise """ try: if not psutil.pid_exists(pid): return False - + proc = psutil.Process(pid) cmdline = " ".join(proc.cmdline()).lower() - + # Check for our application signatures backend_signatures = [ "main.py", "s7_snap7_streamer_n_log", "plc_streamer", - "plcdatastreamer" + "plcdatastreamer", ] - + return any(sig in cmdline for sig in backend_signatures) - + except (psutil.NoSuchProcess, psutil.AccessDenied, psutil.ZombieProcess): return False except Exception as e: print(f"โš ๏ธ Error checking process {pid}: {e}") return False - + def terminate_process_safely(self, pid: int) -> bool: """ Safely terminate a process - + Args: pid: Process ID to terminate - + Returns: True if process was terminated successfully, False otherwise """ try: if not psutil.pid_exists(pid): return True # Already gone - + proc = psutil.Process(pid) print(f"๐Ÿ›‘ Attempting to terminate process {pid} ({proc.name()})...") - + # Try graceful termination first proc.terminate() - + # Wait up to 10 seconds for graceful shutdown try: proc.wait(timeout=10) @@ -152,17 +157,17 @@ class InstanceManager: proc.wait(timeout=5) print(f"๐Ÿ’ฅ Process {pid} force killed") return True - + except (psutil.NoSuchProcess, psutil.AccessDenied): return True # Process already gone or no permission except Exception as e: print(f"โŒ Error terminating process {pid}: {e}") return False - + def cleanup_lock_file(self) -> bool: """ Remove the lock file - + Returns: True if lock file was removed or didn't exist, False on error """ @@ -174,11 +179,11 @@ class InstanceManager: except Exception as e: print(f"โŒ Error removing lock file: {e}") return False - + def create_lock_file(self) -> bool: """ Create lock file with current process PID - + Returns: True if lock file was created successfully, False otherwise """ @@ -190,47 +195,47 @@ class InstanceManager: except Exception as e: print(f"โŒ Error creating lock file: {e}") return False - + def check_and_handle_existing_instance(self) -> Tuple[bool, str]: """ Main method: Check for existing instances and handle them - + Returns: Tuple of (can_proceed, message) - can_proceed: True if this instance can start, False if should exit - message: Description of what happened """ print("๐Ÿ” Checking for existing backend instances...") - + # Step 1: First HTTP health check print("๐Ÿ“ก Performing first health check...") if self.is_backend_alive_http(): return False, f"โŒ Another backend is already running on port {self.port}" - + print(f"โณ Waiting {self.check_interval} seconds for double-check...") time.sleep(self.check_interval) - + # Step 2: Second HTTP health check (double verification) print("๐Ÿ“ก Performing second health check...") if self.is_backend_alive_http(): return False, f"โŒ Another backend is confirmed running on port {self.port}" - + print("โœ… No active backend detected via HTTP") - + # Step 3: Check lock file and handle zombie processes lock_pid = self.get_lock_file_pid() if lock_pid is None: print("๐Ÿ“ No lock file found") return True, "โœ… No existing instances detected" - + print(f"๐Ÿ“‹ Found lock file with PID: {lock_pid}") - + # Step 4: Verify if the process is actually our backend if not self.is_process_our_backend(lock_pid): print(f"๐Ÿงน PID {lock_pid} is not our backend process") self.cleanup_lock_file() return True, "โœ… Cleaned up stale lock file" - + # Step 5: We have a zombie backend process - terminate it print(f"๐ŸงŸ Found zombie backend process (PID: {lock_pid})") if self.terminate_process_safely(lock_pid): @@ -239,35 +244,36 @@ class InstanceManager: return True, "โœ… Cleaned up zombie backend process" else: return False, f"โŒ Failed to cleanup zombie process (PID: {lock_pid})" - + def initialize_instance(self) -> bool: """ Initialize this instance (create lock file) - + Returns: True if initialization successful, False otherwise """ return self.create_lock_file() - + def cleanup_instance(self) -> bool: """ Cleanup this instance (remove lock file) - + Returns: True if cleanup successful, False otherwise """ return self.cleanup_lock_file() -def check_backend_instance(port: int = 5050, - lock_file: str = "plc_streamer.lock") -> Tuple[bool, str]: +def check_backend_instance( + port: int = 5050, lock_file: str = "plc_streamer.lock" +) -> Tuple[bool, str]: """ Convenience function to check and handle backend instances - + Args: port: Backend server port lock_file: Lock file path - + Returns: Tuple of (can_proceed, message) """