@@ -10,6 +10,7 @@ use hyper_util::rt::TokioIo;
1010use log:: { debug, error, info, warn} ;
1111use serde:: Deserialize ;
1212use std:: collections:: HashMap ;
13+ use std:: io:: Write ;
1314use std:: sync:: atomic:: { AtomicUsize , Ordering } ;
1415use std:: sync:: Arc ;
1516use std:: time:: { Duration , Instant } ;
@@ -107,6 +108,12 @@ struct LoadBalancer {
107108 http_client : HttpClient ,
108109}
109110
111+ #[ derive( Debug ) ]
112+ enum HealthProbeError {
113+ Timeout ,
114+ Transport ( String ) ,
115+ }
116+
110117impl LoadBalancer {
111118 fn new (
112119 backends : Vec < Backend > ,
@@ -215,7 +222,26 @@ impl LoadBalancer {
215222 }
216223 } ;
217224
218- match self . http_client . get ( uri) . await {
225+ let request_future = self . http_client . get ( uri) ;
226+ let response_result = if config. timeout_seconds > 0 {
227+ match tokio:: time:: timeout (
228+ Duration :: from_secs ( config. timeout_seconds ) ,
229+ request_future,
230+ )
231+ . await
232+ {
233+ Ok ( inner_result) => {
234+ inner_result. map_err ( |err| HealthProbeError :: Transport ( err. to_string ( ) ) )
235+ }
236+ Err ( _) => Err ( HealthProbeError :: Timeout ) ,
237+ }
238+ } else {
239+ request_future
240+ . await
241+ . map_err ( |err| HealthProbeError :: Transport ( err. to_string ( ) ) )
242+ } ;
243+
244+ match response_result {
219245 Ok ( response) => {
220246 let status = response. status ( ) ;
221247 let mut health = self . health_status . write ( ) . await ;
@@ -240,8 +266,19 @@ impl LoadBalancer {
240266 }
241267 }
242268 }
243- Err ( e) => {
244- debug ! ( "Health check failed for {}: {}" , backend. url, e) ;
269+ Err ( error) => {
270+ match error {
271+ HealthProbeError :: Timeout => {
272+ debug ! (
273+ "Health check timed out for {} after {}s" ,
274+ backend. url, config. timeout_seconds
275+ ) ;
276+ }
277+ HealthProbeError :: Transport ( e) => {
278+ debug ! ( "Health check failed for {}: {}" , backend. url, e) ;
279+ }
280+ }
281+
245282 let mut health = self . health_status . write ( ) . await ;
246283
247284 if let Some ( backend_health) = health. get_mut ( & backend. url ) {
@@ -465,17 +502,32 @@ fn load_config() -> Result<Config> {
465502}
466503
467504fn setup_logging ( config : & LoggingConfig ) {
468- let log_level = match config. level . as_str ( ) {
505+ let level_key = config. level . to_lowercase ( ) ;
506+ let log_level = match level_key. as_str ( ) {
469507 "debug" => log:: LevelFilter :: Debug ,
470508 "info" => log:: LevelFilter :: Info ,
471509 "warn" => log:: LevelFilter :: Warn ,
472510 "error" => log:: LevelFilter :: Error ,
473511 _ => log:: LevelFilter :: Info ,
474512 } ;
475513
476- env_logger:: Builder :: from_default_env ( )
477- . filter_level ( log_level)
478- . init ( ) ;
514+ let mut builder = env_logger:: Builder :: from_default_env ( ) ;
515+ builder. filter_level ( log_level) ;
516+
517+ if config. format . eq_ignore_ascii_case ( "json" ) {
518+ builder. format ( |buf, record| {
519+ let timestamp = Utc :: now ( ) . to_rfc3339 ( ) ;
520+ let payload = serde_json:: json!( {
521+ "timestamp" : timestamp,
522+ "level" : record. level( ) . to_string( ) ,
523+ "target" : record. target( ) ,
524+ "message" : record. args( ) . to_string( ) ,
525+ } ) ;
526+ writeln ! ( buf, "{}" , payload)
527+ } ) ;
528+ }
529+
530+ builder. init ( ) ;
479531}
480532
481533#[ tokio:: main]
0 commit comments