@@ -12,6 +12,9 @@ use spin_factors::RuntimeFactors;
12
12
use spin_factors_executor:: ExecutorHooks ;
13
13
use tokio:: io:: AsyncWrite ;
14
14
15
+ pub const STDOUT_LOG_FILE_SUFFIX : & str = "stdout" ;
16
+ pub const STDERR_LOG_FILE_SUFFIX : & str = "stderr" ;
17
+
15
18
/// Which components should have their logs followed on stdout/stderr.
16
19
#[ derive( Clone , Debug , Default ) ]
17
20
pub enum FollowComponents {
@@ -39,13 +42,19 @@ impl FollowComponents {
39
42
pub struct StdioLoggingExecutorHooks {
40
43
follow_components : FollowComponents ,
41
44
log_dir : Option < PathBuf > ,
45
+ truncate_log : bool ,
42
46
}
43
47
44
48
impl 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
+ truncate_log : bool ,
53
+ ) -> Self {
46
54
Self {
47
55
follow_components,
48
56
log_dir,
57
+ truncate_log,
49
58
}
50
59
}
51
60
@@ -86,6 +95,23 @@ impl StdioLoggingExecutorHooks {
86
95
_ => Ok ( ( ) ) ,
87
96
}
88
97
}
98
+
99
+ fn truncate_log_files ( log_dir : & Path ) {
100
+ if let Ok ( entries) = log_dir. read_dir ( ) {
101
+ for entry in entries. flatten ( ) {
102
+ let path = entry. path ( ) ;
103
+ let Some ( name) = path. file_name ( ) . and_then ( |n| n. to_str ( ) ) else {
104
+ continue ;
105
+ } ;
106
+
107
+ if name. ends_with ( & format ! ( "{STDOUT_LOG_FILE_SUFFIX}.txt" ) )
108
+ || name. ends_with ( & format ! ( "{STDERR_LOG_FILE_SUFFIX}.txt" ) )
109
+ {
110
+ _ = std:: fs:: File :: create ( path)
111
+ }
112
+ }
113
+ }
114
+ }
89
115
}
90
116
91
117
#[ async_trait]
@@ -95,11 +121,16 @@ impl<F: RuntimeFactors, U> ExecutorHooks<F, U> for StdioLoggingExecutorHooks {
95
121
configured_app : & spin_factors:: ConfiguredApp < F > ,
96
122
) -> anyhow:: Result < ( ) > {
97
123
self . validate_follows ( configured_app. app ( ) ) ?;
124
+
98
125
if let Some ( dir) = & self . log_dir {
99
126
// Ensure log dir exists if set
100
127
std:: fs:: create_dir_all ( dir)
101
128
. with_context ( || format ! ( "Failed to create log dir {}" , quoted_path( dir) ) ) ?;
102
129
130
+ if self . truncate_log {
131
+ Self :: truncate_log_files ( dir) ;
132
+ }
133
+
103
134
println ! ( "Logging component stdio to {}" , quoted_path( dir. join( "" ) ) )
104
135
}
105
136
Ok ( ( ) )
@@ -115,12 +146,12 @@ impl<F: RuntimeFactors, U> ExecutorHooks<F, U> for StdioLoggingExecutorHooks {
115
146
} ;
116
147
wasi_builder. stdout_pipe ( self . component_stdio_writer (
117
148
& component_id,
118
- "stdout" ,
149
+ STDOUT_LOG_FILE_SUFFIX ,
119
150
self . log_dir . as_deref ( ) ,
120
151
) ?) ;
121
152
wasi_builder. stderr_pipe ( self . component_stdio_writer (
122
153
& component_id,
123
- "stderr" ,
154
+ STDERR_LOG_FILE_SUFFIX ,
124
155
self . log_dir . as_deref ( ) ,
125
156
) ?) ;
126
157
Ok ( ( ) )
0 commit comments