@@ -12,6 +12,9 @@ use spin_factors::RuntimeFactors;
1212use spin_factors_executor:: ExecutorHooks ;
1313use tokio:: io:: AsyncWrite ;
1414
15+ pub const STDOUT_LOG_FILE_SUFFIX : & str = "stdout" ;
16+ pub const STDERR_LOG_FILE_SUFFIX : & str = "stderr" ;
17+
1518/// Which components should have their logs followed on stdout/stderr.
1619#[ derive( Clone , Debug , Default ) ]
1720pub enum FollowComponents {
@@ -39,13 +42,19 @@ impl FollowComponents {
3942pub struct StdioLoggingExecutorHooks {
4043 follow_components : FollowComponents ,
4144 log_dir : Option < PathBuf > ,
45+ refresh_log : bool ,
4246}
4347
4448impl StdioLoggingExecutorHooks {
45- pub fn new ( follow_components : FollowComponents , log_dir : Option < PathBuf > ) -> Self {
49+ pub fn new (
50+ follow_components : FollowComponents ,
51+ log_dir : Option < PathBuf > ,
52+ refresh_log : bool ,
53+ ) -> Self {
4654 Self {
4755 follow_components,
4856 log_dir,
57+ refresh_log,
4958 }
5059 }
5160
@@ -56,8 +65,7 @@ impl StdioLoggingExecutorHooks {
5665 log_dir : Option < & Path > ,
5766 ) -> Result < ComponentStdioWriter > {
5867 let sanitized_component_id = sanitize_filename:: sanitize ( component_id) ;
59- let log_path = log_dir
60- . map ( |log_dir| log_dir. join ( format ! ( "{sanitized_component_id}_{log_suffix}.txt" , ) ) ) ;
68+ let log_path = santized_log_path ( log_dir, & sanitized_component_id, log_suffix) ;
6169 let log_path = log_path. as_deref ( ) ;
6270
6371 let follow = self . follow_components . should_follow ( component_id) ;
@@ -95,6 +103,33 @@ impl<F: RuntimeFactors, U> ExecutorHooks<F, U> for StdioLoggingExecutorHooks {
95103 configured_app : & spin_factors:: ConfiguredApp < F > ,
96104 ) -> anyhow:: Result < ( ) > {
97105 self . validate_follows ( configured_app. app ( ) ) ?;
106+
107+ if self . refresh_log {
108+ let sanitized_component_ids: Vec < String > = configured_app
109+ . app ( )
110+ . components ( )
111+ . map ( |c| sanitize_filename:: sanitize ( c. locked . id . clone ( ) ) )
112+ . collect ( ) ;
113+
114+ for sanitized_component_id in sanitized_component_ids {
115+ if let Some ( stdout_log_path) = santized_log_path (
116+ self . log_dir . as_deref ( ) ,
117+ & sanitized_component_id,
118+ STDOUT_LOG_FILE_SUFFIX ,
119+ ) {
120+ let _ = std:: fs:: File :: create ( stdout_log_path) ;
121+ }
122+
123+ if let Some ( stderr_log_path) = santized_log_path (
124+ self . log_dir . as_deref ( ) ,
125+ & sanitized_component_id,
126+ STDERR_LOG_FILE_SUFFIX ,
127+ ) {
128+ let _ = std:: fs:: File :: create ( stderr_log_path) ;
129+ }
130+ }
131+ }
132+
98133 if let Some ( dir) = & self . log_dir {
99134 // Ensure log dir exists if set
100135 std:: fs:: create_dir_all ( dir)
@@ -115,12 +150,12 @@ impl<F: RuntimeFactors, U> ExecutorHooks<F, U> for StdioLoggingExecutorHooks {
115150 } ;
116151 wasi_builder. stdout_pipe ( self . component_stdio_writer (
117152 & component_id,
118- "stdout" ,
153+ STDOUT_LOG_FILE_SUFFIX ,
119154 self . log_dir . as_deref ( ) ,
120155 ) ?) ;
121156 wasi_builder. stderr_pipe ( self . component_stdio_writer (
122157 & component_id,
123- "stderr" ,
158+ STDERR_LOG_FILE_SUFFIX ,
124159 self . log_dir . as_deref ( ) ,
125160 ) ?) ;
126161 Ok ( ( ) )
@@ -328,3 +363,11 @@ fn bullet_list<S: std::fmt::Display>(items: impl IntoIterator<Item = S>) -> Stri
328363 . collect :: < Vec < _ > > ( )
329364 . join ( "\n " )
330365}
366+
367+ fn santized_log_path (
368+ log_dir : Option < & Path > ,
369+ sanitized_component_id : & str ,
370+ log_suffix : & str ,
371+ ) -> Option < PathBuf > {
372+ log_dir. map ( |log_dir| log_dir. join ( format ! ( "{sanitized_component_id}_{log_suffix}.txt" , ) ) )
373+ }
0 commit comments