impl Pool { pub fn view(&self) -> Value { let members = self .members .iter() .map(|m| { let h = lock(&m.state.health); let failure = lock(&m.state.last_failure); let member_health = self.settings.health_for(&m.definition); let status = if !m.definition.enabled { "disabled" } else if m.definition.drain { "draining" } else if h.healthy { "up" } else if !h.checked && member_health.mode != HealthMode::Off { "checking" } else { "down" }; let mut item = serde_json::Map::new(); item.insert("id".into(), json!(m.definition.id)); item.insert("url".into(), json!(m.definition.url)); item.insert("protocol".into(), json!(m.definition.protocol)); item.insert("weight".into(), json!(m.definition.weight)); item.insert("backup".into(), json!(m.definition.backup)); item.insert( "health_check_enabled".into(), json!(m.definition.health_check_enabled), ); item.insert("health_mode".into(), json!(member_health.mode)); item.insert( "max_concurrent_requests".into(), json!(m.definition.max_concurrent_requests), ); item.insert( "queue_timeout_ms".into(), json!(m.definition.queue_timeout_ms), ); item.insert("status".into(), json!(status)); item.insert("healthy".into(), json!(h.healthy)); item.insert( "active".into(), json!(m.state.active.load(Ordering::Relaxed)), ); item.insert( "requests".into(), json!(m.state.requests.load(Ordering::Relaxed)), ); item.insert( "errors".into(), json!(m.state.errors.load(Ordering::Relaxed)), ); item.insert( "bytes_in".into(), json!(m.state.bytes_in.load(Ordering::Relaxed)), ); item.insert( "bytes_out".into(), json!(m.state.bytes_out.load(Ordering::Relaxed)), ); item.insert( "traffic_bytes_per_second".into(), json!(m.state.traffic_rate()), ); let client_rotation = m.backend.client.rotation_stats(); item.insert( "upstream_client_generation".into(), json!(client_rotation.generation), ); item.insert( "upstream_client_generation_requests".into(), json!(client_rotation.generation_requests), ); item.insert( "upstream_client_generation_age_seconds".into(), json!(client_rotation.generation_age_seconds), ); item.insert( "upstream_client_rotations_total".into(), json!(client_rotation.rotations), ); let observed = m.backend.client.protocol_stats(); item.insert( "upstream_protocol_observed".into(), json!(observed.last_version), ); item.insert( "upstream_protocol_last_seen_ms".into(), json!(observed.observed_at_ms), ); item.insert( "upstream_protocol_http1_total".into(), json!(observed.http1_responses), ); item.insert( "upstream_protocol_http2_total".into(), json!(observed.http2_responses), ); item.insert("latency_ms".into(), json!(h.latency_us as f64 / 1000.0)); item.insert("ewma_latency_ms".into(), json!(h.ewma_us as f64 / 1000.0)); item.insert("last_probe_ms".into(), json!(h.last_probe_ms)); item.insert("last_result".into(), json!(h.result)); item.insert("last_passive_result".into(), json!(h.passive_result)); item.insert("failures".into(), json!(h.failures)); item.insert("passive_failures".into(), json!(h.passive_failures)); item.insert("successes".into(), json!(h.successes)); item.insert("passive_successes".into(), json!(h.passive_successes)); item.insert("transitions".into(), json!(h.transitions)); item.insert("unhealthy_source".into(), json!(h.unhealthy_source)); item.insert("unhealthy_reason".into(), json!(h.unhealthy_reason)); item.insert( "http_5xx_total".into(), json!(m.state.http_5xx_total.load(Ordering::Relaxed)), ); item.insert( "timeouts_total".into(), json!(m.state.timeouts_total.load(Ordering::Relaxed)), ); item.insert( "connect_errors_total".into(), json!(m.state.connect_errors_total.load(Ordering::Relaxed)), ); item.insert( "io_errors_total".into(), json!(m.state.io_errors_total.load(Ordering::Relaxed)), ); item.insert( "slow_responses_total".into(), json!(m.state.slow_responses_total.load(Ordering::Relaxed)), ); item.insert( "retry_attempts_total".into(), json!(m.state.retry_attempts_total.load(Ordering::Relaxed)), ); item.insert( "retry_successes_total".into(), json!(m.state.retry_successes_total.load(Ordering::Relaxed)), ); item.insert( "capacity_rejections_total".into(), json!(m.state.capacity_rejections_total.load(Ordering::Relaxed)), ); item.insert( "queue_timeouts_total".into(), json!(m.state.queue_timeouts_total.load(Ordering::Relaxed)), ); item.insert( "dns_errors_total".into(), json!(m.state.dns_errors_total.load(Ordering::Relaxed)), ); item.insert( "tls_errors_total".into(), json!(m.state.tls_errors_total.load(Ordering::Relaxed)), ); item.insert( "response_header_timeouts_total".into(), json!(m .state .response_header_timeouts_total .load(Ordering::Relaxed)), ); item.insert( "read_timeouts_total".into(), json!(m.state.read_timeouts_total.load(Ordering::Relaxed)), ); item.insert( "send_timeouts_total".into(), json!(m.state.send_timeouts_total.load(Ordering::Relaxed)), ); item.insert("last_failure_at_ms".into(), json!(failure.at_ms)); item.insert("last_failure_class".into(), json!(failure.class)); item.insert("last_failure_detail".into(), json!(failure.detail.as_str())); item.insert( "last_ejected_ms".into(), json!(m.state.last_ejected_ms.load(Ordering::Relaxed)), ); item.insert( "last_recovered_ms".into(), json!(m.state.last_recovered_ms.load(Ordering::Relaxed)), ); item.insert( "active_health_failures_total".into(), json!(m.state.active_health_failures_total.load(Ordering::Relaxed)), ); item.insert( "passive_health_failures_total".into(), json!(m .state .passive_health_failures_total .load(Ordering::Relaxed)), ); item.insert( "last_status".into(), json!(m.state.last_status.load(Ordering::Relaxed)), ); Value::Object(item) }) .collect::>(); json!({ "id": self.id, "algorithm": self.settings.algorithm, "ready": self.ready(), "health_mode": self.settings.health_check.mode, "passive_health": self.settings.passive_health, "retry": self.settings.retry, "sticky_mode": self.settings.sticky.mode, "keepalive": self.settings.keepalive, "members": members, }) } }