1 // Copyright 2022 The ChromiumOS Authors 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 //! Encapsulate the main runtime loop of a metrics process. 6 7 use anyhow::Result; 8 use base::info; 9 use base::warn; 10 use base::EventToken; 11 use base::Tube; 12 13 use crate::metrics_requests::MetricsRequest; 14 use crate::RequestHandler; 15 16 /// Handles incoming requests to log metrics 17 pub(crate) trait MetricsRequestHandler { new() -> Self18 fn new() -> Self; handle_request(&self, request: MetricsRequest)19 fn handle_request(&self, request: MetricsRequest); shutdown(&self)20 fn shutdown(&self); 21 } 22 23 /// Runs the metrics controller. 24 pub struct MetricsController { 25 pub(crate) agents: Vec<Tube>, 26 handler: RequestHandler, 27 pub(crate) closed_tubes: usize, 28 } 29 30 #[derive(EventToken)] 31 pub(crate) enum MetricsControllerToken { 32 /// Triggered when the agent's pipe is readable (e.g. read_notifier). 33 Agent(usize), 34 /// Triggered when the agent's pipe closes (e.g. close_notifier). 35 #[cfg(windows)] 36 AgentExited(usize), 37 } 38 39 impl MetricsController { new(agents: Vec<Tube>) -> Self40 pub fn new(agents: Vec<Tube>) -> Self { 41 Self { 42 agents, 43 handler: RequestHandler::new(), 44 closed_tubes: 0, 45 } 46 } 47 48 /// Run the metrics controller until all clients exit & close their Tubes. run(&mut self) -> Result<()>49 pub fn run(&mut self) -> Result<()> { 50 self.run_internal()?; 51 self.handler.shutdown(); 52 Ok(()) 53 } 54 55 /// Handles a tube that has indicated it has data ready to read. on_tube_readable(&self, client: &Tube)56 pub(crate) fn on_tube_readable(&self, client: &Tube) { 57 match client.recv::<MetricsRequest>() { 58 Ok(req) => self.handler.handle_request(req), 59 Err(e) => { 60 warn!("unexpected error receiving agent metrics request: {}", e) 61 } 62 } 63 } 64 65 /// Handles a closed connection, and returns a bool indicating 66 /// whether the run loop itself should close. on_connection_closed(&mut self) -> bool67 pub(crate) fn on_connection_closed(&mut self) -> bool { 68 self.closed_tubes += 1; 69 info!( 70 "metrics tube closed: {} out of {} closed", 71 self.closed_tubes, 72 self.agents.len(), 73 ); 74 if self.closed_tubes == self.agents.len() { 75 info!("metrics run loop exiting: all tubes closed"); 76 return true; 77 } 78 79 false 80 } 81 } 82