rust_ethernet_ip/client/
diagnostics.rs1use super::EipClient;
2use tokio::time::Duration;
3
4impl EipClient {
5 pub async fn check_health(&self) -> bool {
11 self.session_handle() != 0
12 && self.last_activity.lock().await.elapsed() < Duration::from_secs(150)
13 }
14
15 pub async fn get_diagnostics_snapshot(&self) -> crate::DiagnosticsSnapshot {
17 self.build_diagnostics_snapshot(crate::HealthCheckMode::Passive, self.check_health().await)
18 .await
19 }
20
21 pub async fn check_health_detailed(&mut self) -> crate::error::Result<bool> {
27 if self.session_handle() == 0 {
28 return Ok(false);
29 }
30
31 match self.send_keep_alive().await {
33 Ok(()) => Ok(true),
34 Err(_) => {
35 match self.register_session().await {
38 Ok(()) => Ok(true),
39 Err(_) => Ok(false),
40 }
41 }
42 }
43 }
44
45 pub async fn get_diagnostics_snapshot_detailed(
47 &mut self,
48 ) -> crate::error::Result<crate::DiagnosticsSnapshot> {
49 let is_healthy = self.check_health_detailed().await?;
50 Ok(self
51 .build_diagnostics_snapshot(crate::HealthCheckMode::Verified, is_healthy)
52 .await)
53 }
54
55 pub fn schema_cache_metrics(&self) -> crate::SchemaCacheMetrics {
57 crate::SchemaCacheMetrics {
58 generation: self.schema_generation(),
59 refreshes: self
60 .diagnostic_counters
61 .schema_refreshes
62 .load(std::sync::atomic::Ordering::Relaxed),
63 array_classification_hits: self
64 .diagnostic_counters
65 .array_cache_hits
66 .load(std::sync::atomic::Ordering::Relaxed),
67 array_classification_misses: self
68 .diagnostic_counters
69 .array_cache_misses
70 .load(std::sync::atomic::Ordering::Relaxed),
71 array_classification_evictions: self
72 .diagnostic_counters
73 .array_cache_evictions
74 .load(std::sync::atomic::Ordering::Relaxed),
75 datatype_contradictions: self
76 .diagnostic_counters
77 .schema_type_contradictions
78 .load(std::sync::atomic::Ordering::Relaxed),
79 successful_read_recoveries: self
80 .diagnostic_counters
81 .schema_read_recoveries_succeeded
82 .load(std::sync::atomic::Ordering::Relaxed),
83 failed_read_recoveries: self
84 .diagnostic_counters
85 .schema_read_recoveries_failed
86 .load(std::sync::atomic::Ordering::Relaxed),
87 }
88 }
89
90 async fn build_diagnostics_snapshot(
91 &self,
92 health_mode: crate::HealthCheckMode,
93 is_healthy: bool,
94 ) -> crate::DiagnosticsSnapshot {
95 let now = std::time::SystemTime::now();
96 let session_active = self.session_handle() != 0;
97 let last_activity_elapsed = self.last_activity.lock().await.elapsed();
98 let last_success_time = if is_healthy || session_active {
99 Some(
100 now.checked_sub(last_activity_elapsed)
101 .unwrap_or(std::time::SystemTime::UNIX_EPOCH),
102 )
103 } else {
104 None
105 };
106
107 let error_category = if session_active && !is_healthy {
108 Some(crate::ErrorCategory::Session)
109 } else {
110 None
111 };
112
113 let operations = self.diagnostic_counters.operation_metrics();
114 let mut errors = self.diagnostic_counters.error_metrics();
115 if error_category == Some(crate::ErrorCategory::Session) {
116 errors.session_errors += 1;
117 errors.retriable_errors += 1;
118 if errors.last_error_time.is_none() {
119 errors.last_error_time = Some(now);
120 errors.last_error_message = Some(
121 "Detailed health check reported session-level connectivity failure".to_string(),
122 );
123 errors.last_error_category = error_category;
124 errors.last_retriable_error_time = Some(now);
125 }
126 }
127
128 crate::DiagnosticsSnapshot {
129 captured_at: now,
130 connections: crate::ConnectionMetrics {
131 active_connections: if session_active { 1 } else { 0 },
132 total_connections: if session_active { 1 } else { 0 },
133 failed_connections: 0,
134 connection_uptime_avg: Duration::ZERO,
135 last_connection_time: last_success_time,
136 },
137 operations,
138 performance: crate::PerformanceMetrics {
139 avg_read_latency_ms: 0.0,
140 avg_write_latency_ms: 0.0,
141 max_read_latency_ms: 0.0,
142 max_write_latency_ms: 0.0,
143 reads_per_second: 0.0,
144 writes_per_second: 0.0,
145 memory_usage_mb: 0.0,
146 cpu_usage_percent: 0.0,
147 },
148 errors,
149 health: crate::HealthMetrics {
150 overall_health: if is_healthy {
151 crate::HealthStatus::Healthy
152 } else if session_active {
153 crate::HealthStatus::Critical
154 } else {
155 crate::HealthStatus::Unknown
156 },
157 last_health_check: now,
158 health_mode,
159 last_verified_health_check: if health_mode == crate::HealthCheckMode::Verified {
160 Some(now)
161 } else {
162 None
163 },
164 consecutive_failures: if is_healthy { 0 } else { 1 },
165 recovery_attempts: 0,
166 system_uptime: Duration::ZERO,
167 last_success_time,
168 last_failure_time: if session_active && !is_healthy {
169 Some(now)
170 } else {
171 None
172 },
173 },
174 system_metrics_are_placeholders: true,
175 }
176 }
177}