@@ -8,6 +8,7 @@ use tracing::{info, warn};
88use super :: BroadcastedMessageMetadata ;
99use crate :: gossipsub_impl:: Topic ;
1010use crate :: misconduct_score:: MisconductScore ;
11+ use crate :: network_manager:: metrics:: NetworkMetrics ;
1112use crate :: peer_manager:: ReputationModifier ;
1213use crate :: sqmr:: behaviour:: SessionIdNotFoundError ;
1314use crate :: sqmr:: { InboundSessionId , OutboundSessionId , SessionId } ;
@@ -48,6 +49,8 @@ pub trait SwarmTrait: Stream<Item = Event> + Unpin {
4849 fn add_new_supported_inbound_protocol ( & mut self , protocol_name : StreamProtocol ) ;
4950
5051 fn continue_propagation ( & mut self , message_metadata : BroadcastedMessageMetadata ) ;
52+
53+ fn update_metrics ( & self , metrics : & NetworkMetrics ) ;
5154}
5255
5356impl SwarmTrait for Swarm < mixed_behaviour:: MixedBehaviour > {
@@ -122,4 +125,93 @@ impl SwarmTrait for Swarm<mixed_behaviour::MixedBehaviour> {
122125
123126 // TODO(shahak): Implement this function.
124127 fn continue_propagation ( & mut self , _message_metadata : BroadcastedMessageMetadata ) { }
128+
129+ fn update_metrics ( & self , metrics : & NetworkMetrics ) {
130+ let Some ( gossipsub_metrics) = & metrics. gossipsub_metrics else { return } ;
131+ let gossipsub = & self . behaviour ( ) . gossipsub ;
132+
133+ // Helper to convert usize counts to f64 metrics
134+ let set_count = |gauge : & apollo_metrics:: metrics:: MetricGauge , count : usize | {
135+ gauge. set ( f64:: from ( u32:: try_from ( count) . unwrap_or ( u32:: MAX ) ) ) ;
136+ } ;
137+
138+ // Basic counts
139+ set_count ( & gossipsub_metrics. num_mesh_peers , gossipsub. all_mesh_peers ( ) . count ( ) ) ;
140+ set_count ( & gossipsub_metrics. num_subscribed_topics , gossipsub. topics ( ) . count ( ) ) ;
141+
142+ // Collect peer data once for analysis
143+ let all_peers: Vec < _ > = gossipsub. all_peers ( ) . collect ( ) ;
144+ set_count ( & gossipsub_metrics. num_all_peers , all_peers. len ( ) ) ;
145+ set_count ( & gossipsub_metrics. num_gossipsub_peers , gossipsub. peer_protocol ( ) . count ( ) ) ;
146+ gossipsub_metrics. num_floodsub_peers . set ( 0.0 ) ; // Currently all peers are gossipsub
147+
148+ // Topic subscription analysis
149+ let topic_counts: Vec < usize > = all_peers. iter ( ) . map ( |( _, topics) | topics. len ( ) ) . collect ( ) ;
150+ let total_subscriptions: usize = topic_counts. iter ( ) . sum ( ) ;
151+ set_count ( & gossipsub_metrics. total_topic_subscriptions , total_subscriptions) ;
152+
153+ if topic_counts. is_empty ( ) {
154+ [
155+ & gossipsub_metrics. avg_topics_per_peer ,
156+ & gossipsub_metrics. max_topics_per_peer ,
157+ & gossipsub_metrics. min_topics_per_peer ,
158+ ]
159+ . iter ( )
160+ . for_each ( |metric| metric. set ( 0.0 ) ) ;
161+ } else {
162+ let avg = f64:: from ( u32:: try_from ( total_subscriptions) . unwrap_or ( u32:: MAX ) ) / f64:: from ( u32:: try_from ( topic_counts. len ( ) ) . unwrap_or ( u32:: MAX ) ) ;
163+ gossipsub_metrics. avg_topics_per_peer . set ( avg) ;
164+
165+ if let ( Some ( & max) , Some ( & min_non_zero) ) =
166+ ( topic_counts. iter ( ) . max ( ) , topic_counts. iter ( ) . filter ( |& & c| c > 0 ) . min ( ) )
167+ {
168+ set_count ( & gossipsub_metrics. max_topics_per_peer , max) ;
169+ set_count ( & gossipsub_metrics. min_topics_per_peer , min_non_zero) ;
170+ }
171+ }
172+
173+ // Mesh analysis per topic
174+ let our_topics: Vec < _ > = gossipsub. topics ( ) . collect ( ) ;
175+ if our_topics. is_empty ( ) {
176+ [
177+ & gossipsub_metrics. avg_mesh_peers_per_topic ,
178+ & gossipsub_metrics. max_mesh_peers_per_topic ,
179+ & gossipsub_metrics. min_mesh_peers_per_topic ,
180+ ]
181+ . iter ( )
182+ . for_each ( |metric| metric. set ( 0.0 ) ) ;
183+ } else {
184+ let mesh_counts: Vec < usize > =
185+ our_topics. iter ( ) . map ( |topic| gossipsub. mesh_peers ( topic) . count ( ) ) . collect ( ) ;
186+ let total_mesh = mesh_counts. iter ( ) . sum :: < usize > ( ) ;
187+ let avg_mesh = f64:: from ( u32:: try_from ( total_mesh) . unwrap_or ( u32:: MAX ) ) / f64:: from ( u32:: try_from ( our_topics. len ( ) ) . unwrap_or ( u32:: MAX ) ) ;
188+ gossipsub_metrics. avg_mesh_peers_per_topic . set ( avg_mesh) ;
189+
190+ if let ( Some ( & min) , Some ( & max) ) = ( mesh_counts. iter ( ) . min ( ) , mesh_counts. iter ( ) . max ( ) ) {
191+ set_count ( & gossipsub_metrics. min_mesh_peers_per_topic , min) ;
192+ set_count ( & gossipsub_metrics. max_mesh_peers_per_topic , max) ;
193+ }
194+ }
195+
196+ // Peer scoring analysis
197+ let peer_scores: Vec < f64 > =
198+ all_peers. iter ( ) . filter_map ( |( peer_id, _) | gossipsub. peer_score ( peer_id) ) . collect ( ) ;
199+ if peer_scores. is_empty ( ) {
200+ [
201+ & gossipsub_metrics. num_peers_with_positive_score ,
202+ & gossipsub_metrics. num_peers_with_negative_score ,
203+ & gossipsub_metrics. avg_peer_score ,
204+ ]
205+ . iter ( )
206+ . for_each ( |metric| metric. set ( 0.0 ) ) ;
207+ } else {
208+ let positive_count = peer_scores. iter ( ) . filter ( |& & score| score > 0.0 ) . count ( ) ;
209+ let negative_count = peer_scores. iter ( ) . filter ( |& & score| score < 0.0 ) . count ( ) ;
210+ let avg_score = peer_scores. iter ( ) . sum :: < f64 > ( ) / f64:: from ( u32:: try_from ( peer_scores. len ( ) ) . unwrap_or ( u32:: MAX ) ) ;
211+
212+ set_count ( & gossipsub_metrics. num_peers_with_positive_score , positive_count) ;
213+ set_count ( & gossipsub_metrics. num_peers_with_negative_score , negative_count) ;
214+ gossipsub_metrics. avg_peer_score . set ( avg_score) ;
215+ }
216+ }
125217}
0 commit comments