1- // src/statistics.rs
1+ // src/storage/statistics.rs
2+
23use actix_web:: {
3- dev:: { Service , ServiceRequest , ServiceResponse , Transform } ,
4+ dev:: { ServiceRequest , ServiceResponse , Transform } ,
45 get,
5- web:: { Data } ,
6- HttpResponse , Responder ,
6+ web:: Data ,
7+ HttpResponse ,
8+ Responder ,
79} ;
810use futures_util:: future:: { ok, LocalBoxFuture , Ready } ;
911use serde:: Serialize ;
@@ -16,7 +18,8 @@ use std::{
1618 task:: { Context , Poll } ,
1719 time:: Instant ,
1820} ;
19- use crate :: storage:: engine:: AppState ;
21+
22+ use crate :: storage:: engine:: { AppState , ClusterData } ;
2023use crate :: storage:: subscription:: SubscriptionManager ;
2124
2225/// Holds global counters.
@@ -53,7 +56,7 @@ impl MetricsMiddleware {
5356
5457impl < S , B > Transform < S , ServiceRequest > for MetricsMiddleware
5558where
56- S : Service < ServiceRequest , Response = ServiceResponse < B > , Error = actix_web:: Error >
59+ S : actix_web :: dev :: Service < ServiceRequest , Response = ServiceResponse < B > , Error = actix_web:: Error >
5760 + ' static ,
5861 B : ' static ,
5962{
@@ -76,9 +79,9 @@ pub struct MetricsMiddlewareService<S> {
7679 collector : MetricsCollector ,
7780}
7881
79- impl < S , B > Service < ServiceRequest > for MetricsMiddlewareService < S >
82+ impl < S , B > actix_web :: dev :: Service < ServiceRequest > for MetricsMiddlewareService < S >
8083where
81- S : Service < ServiceRequest , Response = ServiceResponse < B > , Error = actix_web:: Error >
84+ S : actix_web :: dev :: Service < ServiceRequest , Response = ServiceResponse < B > , Error = actix_web:: Error >
8285 + ' static ,
8386 B : ' static ,
8487{
9497 let collector = self . collector . clone ( ) ;
9598 let start = Instant :: now ( ) ;
9699 let fut = self . service . call ( req) ;
100+
97101 Box :: pin ( async move {
98102 let res = fut. await ?;
99103 let latency = start. elapsed ( ) . as_nanos ( ) as u64 ;
@@ -103,13 +107,21 @@ where
103107 }
104108}
105109
110+ #[ derive( Serialize ) ]
111+ struct ClusterStats {
112+ status : String ,
113+ last_heartbeat : u128 ,
114+ }
115+
106116#[ derive( Serialize ) ]
107117struct StatsResponse {
108118 tables : HashMap < String , usize > ,
109119 total_keys : usize ,
110120 total_requests : u64 ,
111121 average_latency_ms : f64 ,
112122 active_sse_connections : usize ,
123+ /// Current cluster membership with status and last heartbeat
124+ cluster : HashMap < String , ClusterStats > ,
113125}
114126
115127/// GET /stats
@@ -118,8 +130,9 @@ pub async fn get_stats(
118130 state : Data < AppState > ,
119131 sub : Data < SubscriptionManager > ,
120132 metrics : Data < MetricsCollector > ,
133+ cluster_data : Data < ClusterData > ,
121134) -> impl Responder {
122- // count keys per table
135+ // Count keys per table.
123136 let store = state. store . read ( ) . await ;
124137 let mut tables = HashMap :: new ( ) ;
125138 let mut total_keys = 0 ;
@@ -128,27 +141,45 @@ pub async fn get_stats(
128141 total_keys += map. len ( ) ;
129142 }
130143
144+ // Compute request stats.
131145 let total_requests = metrics. total_requests . load ( Ordering :: Relaxed ) ;
132146 let total_latency_ns = metrics. total_latency_ns . load ( Ordering :: Relaxed ) ;
133- let avg_latency_ms = if total_requests > 0 {
147+ let average_latency_ms = if total_requests > 0 {
134148 ( total_latency_ns as f64 / total_requests as f64 ) / 1e6
135149 } else {
136150 0.0
137151 } ;
138152
139- // SSE connections = sum of receiver_count() across all channels
153+ // Count active SSE connections.
140154 let channels = sub. channels . read ( ) . await ;
141- let active_sse_connections = channels
142- . values ( )
143- . map ( |tx| tx. receiver_count ( ) )
144- . sum ( ) ;
155+ let active_sse_connections = channels. values ( ) . map ( |tx| tx. receiver_count ( ) ) . sum ( ) ;
156+
157+ // Build cluster membership map.
158+ let cluster = {
159+ let nodes = cluster_data. nodes . read ( ) . await ;
160+ nodes
161+ . iter ( )
162+ . map ( |( addr, info) | {
163+ let status_str = format ! ( "{:?}" , info. status) ;
164+ (
165+ addr. clone ( ) ,
166+ ClusterStats {
167+ status : status_str,
168+ last_heartbeat : info. last_heartbeat ,
169+ } ,
170+ )
171+ } )
172+ . collect :: < HashMap < _ , _ > > ( )
173+ } ;
145174
146175 let resp = StatsResponse {
147176 tables,
148177 total_keys,
149178 total_requests,
150- average_latency_ms : avg_latency_ms ,
179+ average_latency_ms,
151180 active_sse_connections,
181+ cluster,
152182 } ;
183+
153184 HttpResponse :: Ok ( ) . json ( resp)
154185}
0 commit comments