@@ -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
@@ -56,8 +65,7 @@ impl StdioLoggingExecutorHooks {
56
65
log_dir : Option < & Path > ,
57
66
) -> Result < ComponentStdioWriter > {
58
67
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 = sanitized_log_path ( log_dir, & sanitized_component_id, log_suffix) ;
61
69
let log_path = log_path. as_deref ( ) ;
62
70
63
71
let follow = self . follow_components . should_follow ( component_id) ;
@@ -86,6 +94,35 @@ impl StdioLoggingExecutorHooks {
86
94
_ => Ok ( ( ) ) ,
87
95
}
88
96
}
97
+
98
+ fn truncate_log_files < F : RuntimeFactors > (
99
+ & self ,
100
+ configured_app : & spin_factors:: ConfiguredApp < F > ,
101
+ ) {
102
+ let sanitized_component_ids: Vec < String > = configured_app
103
+ . app ( )
104
+ . components ( )
105
+ . map ( |c| sanitize_filename:: sanitize ( c. locked . id . clone ( ) ) )
106
+ . collect ( ) ;
107
+
108
+ for sanitized_component_id in sanitized_component_ids {
109
+ if let Some ( stdout_log_path) = sanitized_log_path (
110
+ self . log_dir . as_deref ( ) ,
111
+ & sanitized_component_id,
112
+ STDOUT_LOG_FILE_SUFFIX ,
113
+ ) {
114
+ _ = std:: fs:: File :: create ( stdout_log_path) ;
115
+ }
116
+
117
+ if let Some ( stderr_log_path) = sanitized_log_path (
118
+ self . log_dir . as_deref ( ) ,
119
+ & sanitized_component_id,
120
+ STDERR_LOG_FILE_SUFFIX ,
121
+ ) {
122
+ _ = std:: fs:: File :: create ( stderr_log_path) ;
123
+ }
124
+ }
125
+ }
89
126
}
90
127
91
128
#[ async_trait]
@@ -95,11 +132,16 @@ impl<F: RuntimeFactors, U> ExecutorHooks<F, U> for StdioLoggingExecutorHooks {
95
132
configured_app : & spin_factors:: ConfiguredApp < F > ,
96
133
) -> anyhow:: Result < ( ) > {
97
134
self . validate_follows ( configured_app. app ( ) ) ?;
135
+
98
136
if let Some ( dir) = & self . log_dir {
99
137
// Ensure log dir exists if set
100
138
std:: fs:: create_dir_all ( dir)
101
139
. with_context ( || format ! ( "Failed to create log dir {}" , quoted_path( dir) ) ) ?;
102
140
141
+ if self . truncate_log {
142
+ self . truncate_log_files ( configured_app) ;
143
+ }
144
+
103
145
println ! ( "Logging component stdio to {}" , quoted_path( dir. join( "" ) ) )
104
146
}
105
147
Ok ( ( ) )
@@ -115,12 +157,12 @@ impl<F: RuntimeFactors, U> ExecutorHooks<F, U> for StdioLoggingExecutorHooks {
115
157
} ;
116
158
wasi_builder. stdout_pipe ( self . component_stdio_writer (
117
159
& component_id,
118
- "stdout" ,
160
+ STDOUT_LOG_FILE_SUFFIX ,
119
161
self . log_dir . as_deref ( ) ,
120
162
) ?) ;
121
163
wasi_builder. stderr_pipe ( self . component_stdio_writer (
122
164
& component_id,
123
- "stderr" ,
165
+ STDERR_LOG_FILE_SUFFIX ,
124
166
self . log_dir . as_deref ( ) ,
125
167
) ?) ;
126
168
Ok ( ( ) )
@@ -328,3 +370,11 @@ fn bullet_list<S: std::fmt::Display>(items: impl IntoIterator<Item = S>) -> Stri
328
370
. collect :: < Vec < _ > > ( )
329
371
. join ( "\n " )
330
372
}
373
+
374
+ fn sanitized_log_path (
375
+ log_dir : Option < & Path > ,
376
+ sanitized_component_id : & str ,
377
+ log_suffix : & str ,
378
+ ) -> Option < PathBuf > {
379
+ log_dir. map ( |log_dir| log_dir. join ( format ! ( "{sanitized_component_id}_{log_suffix}.txt" , ) ) )
380
+ }
0 commit comments