@@ -31,6 +31,7 @@ use anyhow::Context as _;
3131use bytes:: { buf:: BufMut , Bytes , BytesMut } ;
3232use filetime:: FileTime ;
3333use fs:: metadata;
34+ use fs:: File ;
3435use fs_err as fs;
3536use futures:: channel:: mpsc;
3637use futures:: future:: FutureExt ;
@@ -42,15 +43,15 @@ use std::collections::{HashMap, HashSet};
4243use std:: env;
4344use std:: ffi:: OsString ;
4445use std:: future:: Future ;
45- use std:: io:: { self , Write } ;
46+ use std:: io:: { self , BufWriter , Write } ;
4647use std:: marker:: Unpin ;
4748#[ cfg( feature = "dist-client" ) ]
4849use std:: mem;
4950#[ cfg( target_os = "android" ) ]
5051use std:: os:: android:: net:: SocketAddrExt ;
5152#[ cfg( target_os = "linux" ) ]
5253use std:: os:: linux:: net:: SocketAddrExt ;
53- use std:: path:: PathBuf ;
54+ use std:: path:: { Path , PathBuf } ;
5455use std:: pin:: Pin ;
5556use std:: process:: { ExitStatus , Output } ;
5657use std:: sync:: Arc ;
@@ -488,8 +489,14 @@ pub fn start_server(config: &Config, addr: &crate::net::SocketAddr) -> Result<()
488489 crate :: net:: SocketAddr :: Net ( addr) => {
489490 trace ! ( "binding TCP {addr}" ) ;
490491 let l = runtime. block_on ( tokio:: net:: TcpListener :: bind ( addr) ) ?;
491- let srv =
492- SccacheServer :: < _ > :: with_listener ( l, runtime, client, dist_client, storage) ;
492+ let srv = SccacheServer :: < _ > :: with_listener (
493+ l,
494+ runtime,
495+ client,
496+ dist_client,
497+ storage,
498+ config. cache_stats_file . clone ( ) ,
499+ ) ;
493500 Ok ( (
494501 srv. local_addr ( ) . unwrap ( ) ,
495502 Box :: new ( move |f| srv. run ( f) ) as Box < dyn FnOnce ( _) -> _ > ,
@@ -504,8 +511,14 @@ pub fn start_server(config: &Config, addr: &crate::net::SocketAddr) -> Result<()
504511 let _guard = runtime. enter ( ) ;
505512 tokio:: net:: UnixListener :: bind ( path) ?
506513 } ;
507- let srv =
508- SccacheServer :: < _ > :: with_listener ( l, runtime, client, dist_client, storage) ;
514+ let srv = SccacheServer :: < _ > :: with_listener (
515+ l,
516+ runtime,
517+ client,
518+ dist_client,
519+ storage,
520+ config. cache_stats_file . clone ( ) ,
521+ ) ;
509522 Ok ( (
510523 srv. local_addr ( ) . unwrap ( ) ,
511524 Box :: new ( move |f| srv. run ( f) ) as Box < dyn FnOnce ( _) -> _ > ,
@@ -521,8 +534,14 @@ pub fn start_server(config: &Config, addr: &crate::net::SocketAddr) -> Result<()
521534 let _guard = runtime. enter ( ) ;
522535 tokio:: net:: UnixListener :: from_std ( l) ?
523536 } ;
524- let srv =
525- SccacheServer :: < _ > :: with_listener ( l, runtime, client, dist_client, storage) ;
537+ let srv = SccacheServer :: < _ > :: with_listener (
538+ l,
539+ runtime,
540+ client,
541+ dist_client,
542+ storage,
543+ config. cache_stats_file . clone ( ) ,
544+ ) ;
526545 Ok ( (
527546 srv. local_addr ( )
528547 . unwrap_or_else ( || crate :: net:: SocketAddr :: UnixAbstract ( p. to_vec ( ) ) ) ,
@@ -579,6 +598,7 @@ impl<C: CommandCreatorSync> SccacheServer<tokio::net::TcpListener, C> {
579598 client : Client ,
580599 dist_client : DistClientContainer ,
581600 storage : Arc < dyn Storage > ,
601+ cache_stats_file : Option < PathBuf > ,
582602 ) -> Result < Self > {
583603 let addr = crate :: net:: SocketAddr :: with_port ( port) ;
584604 let listener = runtime. block_on ( tokio:: net:: TcpListener :: bind ( addr. as_net ( ) . unwrap ( ) ) ) ?;
@@ -589,6 +609,7 @@ impl<C: CommandCreatorSync> SccacheServer<tokio::net::TcpListener, C> {
589609 client,
590610 dist_client,
591611 storage,
612+ cache_stats_file,
592613 ) )
593614 }
594615}
@@ -600,13 +621,22 @@ impl<A: crate::net::Acceptor, C: CommandCreatorSync> SccacheServer<A, C> {
600621 client : Client ,
601622 dist_client : DistClientContainer ,
602623 storage : Arc < dyn Storage > ,
624+ cache_stats_file : Option < PathBuf > ,
603625 ) -> Self {
604626 // Prepare the service which we'll use to service all incoming TCP
605627 // connections.
606628 let ( tx, rx) = mpsc:: channel ( 1 ) ;
607629 let ( wait, info) = WaitUntilZero :: new ( ) ;
608630 let pool = runtime. handle ( ) . clone ( ) ;
609- let service = SccacheService :: new ( dist_client, storage, & client, pool, tx, info) ;
631+ let service = SccacheService :: new (
632+ dist_client,
633+ storage,
634+ & client,
635+ pool,
636+ tx,
637+ info,
638+ cache_stats_file. clone ( ) ,
639+ ) ;
610640
611641 SccacheServer {
612642 runtime,
@@ -818,6 +848,10 @@ where
818848 /// This field causes [WaitUntilZero] to wait until this struct drops.
819849 #[ allow( dead_code) ]
820850 info : ActiveInfo ,
851+
852+ /// A file that will contain JSON-formatted stats output, written after
853+ /// each compile operation.
854+ cache_stats_file : Option < PathBuf > ,
821855}
822856
823857type SccacheRequest = Message < Request , Body < ( ) > > ;
@@ -857,7 +891,11 @@ where
857891 Request :: Compile ( compile) => {
858892 debug ! ( "handle_client: compile" ) ;
859893 me. stats . lock ( ) . await . compile_requests += 1 ;
860- me. handle_compile ( compile) . await
894+ let resp = me. handle_compile ( compile) . await ;
895+ if let Some ( val) = & me. cache_stats_file {
896+ me. stats . lock ( ) . await . clone ( ) . write ( val) ?
897+ }
898+ resp
861899 }
862900 Request :: GetStats => {
863901 debug ! ( "handle_client: get_stats" ) ;
@@ -916,6 +954,7 @@ where
916954 rt : tokio:: runtime:: Handle ,
917955 tx : mpsc:: Sender < ServerMessage > ,
918956 info : ActiveInfo ,
957+ cache_stats_file : Option < PathBuf > ,
919958 ) -> SccacheService < C > {
920959 SccacheService {
921960 stats : Arc :: default ( ) ,
@@ -927,6 +966,7 @@ where
927966 creator : C :: new ( client) ,
928967 tx,
929968 info,
969+ cache_stats_file,
930970 }
931971 }
932972
@@ -938,6 +978,7 @@ where
938978 let ( _, info) = WaitUntilZero :: new ( ) ;
939979 let client = Client :: new_num ( 1 ) ;
940980 let dist_client = DistClientContainer :: new_disabled ( ) ;
981+ let cache_stats_file = None ;
941982 SccacheService {
942983 stats : Arc :: default ( ) ,
943984 dist_client : Arc :: new ( dist_client) ,
@@ -948,6 +989,7 @@ where
948989 creator : C :: new ( & client) ,
949990 tx,
950991 info,
992+ cache_stats_file,
951993 }
952994 }
953995
@@ -960,6 +1002,7 @@ where
9601002 let ( tx, _) = mpsc:: channel ( 1 ) ;
9611003 let ( _, info) = WaitUntilZero :: new ( ) ;
9621004 let client = Client :: new_num ( 1 ) ;
1005+ let cache_stats_file = None ;
9631006 SccacheService {
9641007 stats : Arc :: default ( ) ,
9651008 dist_client : Arc :: new ( DistClientContainer :: new_with_state ( DistClientState :: Some (
@@ -981,6 +1024,7 @@ where
9811024 creator : C :: new ( & client) ,
9821025 tx,
9831026 info,
1027+ cache_stats_file,
9841028 }
9851029 }
9861030
@@ -1909,6 +1953,19 @@ impl ServerStats {
19091953 ) ;
19101954 }
19111955 }
1956+
1957+ /// Write stats in JSON format to a file.
1958+ fn write ( & self , path : & Path ) -> Result < ( ) > {
1959+ let file = match File :: create ( path) {
1960+ Ok ( f) => f,
1961+ Err ( e) => {
1962+ debug ! ( "Couldn't open stats file for writing: {}" , e) ;
1963+ return Ok ( ( ) ) ;
1964+ }
1965+ } ;
1966+ let mut writer = BufWriter :: new ( file) ;
1967+ Ok ( serde_json:: to_writer ( & mut writer, self ) ?)
1968+ }
19121969}
19131970
19141971fn set_percentage_stat (
0 commit comments