15
15
*/
16
16
17
17
use crate :: runner:: Settings ;
18
- use log:: error;
18
+ use log:: { error, LevelFilter } ;
19
19
use mpsc:: { channel, Sender } ;
20
20
use signal_hook:: consts:: { SIGINT , SIGTERM , TERM_SIGNALS } ;
21
21
use signal_hook:: iterator:: Signals ;
22
+ use std:: io:: { BufRead , BufReader } ;
23
+ use std:: process:: { ChildStderr , ChildStdout , Stdio } ;
22
24
use std:: sync:: mpsc;
23
25
use std:: thread:: JoinHandle ;
24
26
use std:: { process:: Command , thread} ;
@@ -31,6 +33,7 @@ pub enum ServiceError {
31
33
32
34
pub struct Service {
33
35
pub name : String ,
36
+ pub log_level : u8 ,
34
37
}
35
38
36
39
pub fn start_services ( settings : Settings ) {
@@ -54,7 +57,7 @@ pub fn start_services(settings: Settings) {
54
57
let ( sender, receiver) = channel ( ) ;
55
58
let mut threads: Vec < Option < JoinHandle < ( ) > > > = vec ! [ ] ;
56
59
for mut service in services {
57
- threads. push ( service. start ( sender. clone ( ) ) ) ;
60
+ threads. extend ( service. start ( sender. clone ( ) ) ) ;
58
61
}
59
62
60
63
// Spawn a signal handling thread
@@ -101,22 +104,49 @@ pub fn start_services(settings: Settings) {
101
104
}
102
105
103
106
impl Service {
104
- fn new ( name : String ) -> Self {
105
- Self { name }
107
+ fn new ( name : String , log_level : u8 ) -> Self {
108
+ Self { name, log_level }
106
109
}
107
-
108
110
pub fn start (
109
111
& mut self ,
110
112
args : Vec < String > ,
111
113
sender : Sender < Result < ( ) , ServiceError > > ,
112
- ) -> Option < thread :: JoinHandle < ( ) > > {
114
+ ) -> Vec < Option < JoinHandle < ( ) > > > {
113
115
let name = self . name . clone ( ) ;
116
+ let name_str = self . name . clone ( ) ;
117
+
118
+ let level = match self . log_level {
119
+ 0 => LevelFilter :: Error ,
120
+ 1 => LevelFilter :: Warn ,
121
+ 2 => LevelFilter :: Info ,
122
+ 3 => LevelFilter :: Debug ,
123
+ 4 ..=u8:: MAX => LevelFilter :: Trace ,
124
+ } ;
125
+ log:: set_max_level ( level) ;
126
+
127
+ // Create a channel for sending thread handles back to main thread
128
+ let ( handle_sender, handle_receiver) = channel ( ) ;
129
+
130
+ let mut result: Vec < Option < JoinHandle < ( ) > > > = Vec :: new ( ) ;
114
131
115
- Some ( thread:: spawn ( move || {
116
- let mut command = Command :: new ( args[ 0 ] . clone ( ) ) ;
132
+ result . push ( Some ( thread:: spawn ( move || {
133
+ let mut command = Command :: new ( & args[ 0 ] ) ;
117
134
command. args ( & args[ 1 ..] ) ;
118
135
119
- let status = command. status ( ) . expect ( "Failed to execute command" ) ;
136
+ // Capture stdout and stderr
137
+ command. stdout ( Stdio :: piped ( ) ) ;
138
+ command. stderr ( Stdio :: piped ( ) ) ;
139
+
140
+ let mut child = command. spawn ( ) . expect ( "Failed to execute command" ) ;
141
+
142
+ let stdout = child. stdout . take ( ) . unwrap ( ) ;
143
+ let stderr = child. stderr . take ( ) . unwrap ( ) ;
144
+ let handles = start_log_handler ( stdout, stderr, name_str) ;
145
+
146
+ // Send the handles back to main thread
147
+ handle_sender. send ( handles) . unwrap ( ) ;
148
+
149
+ let status = child. wait ( ) . expect ( "Failed to wait for command" ) ;
120
150
121
151
if status. success ( ) {
122
152
sender. send ( Ok ( ( ) ) ) . unwrap ( ) ;
@@ -126,12 +156,17 @@ impl Service {
126
156
. send ( Err ( ServiceError :: ThreadError ( error_message) ) )
127
157
. unwrap ( ) ;
128
158
}
129
- } ) )
159
+ } ) ) ) ;
160
+ // Receive the handles from the channel and add them to the result vector
161
+ let received_handles: Vec < Option < JoinHandle < ( ) > > > = handle_receiver. recv ( ) . unwrap ( ) ;
162
+ result. extend ( received_handles) ;
163
+
164
+ result
130
165
}
131
166
}
132
167
133
168
pub trait RunnerService {
134
- fn start ( & mut self , sender : Sender < Result < ( ) , ServiceError > > ) -> Option < JoinHandle < ( ) > > ;
169
+ fn start ( & mut self , sender : Sender < Result < ( ) , ServiceError > > ) -> Vec < Option < JoinHandle < ( ) > > > ;
135
170
}
136
171
137
172
pub struct CondureService {
@@ -147,12 +182,10 @@ impl CondureService {
147
182
args. push ( settings. condure_bin . display ( ) . to_string ( ) ) ;
148
183
149
184
let log_level = match settings. log_levels . get ( service_name) {
150
- Some ( & x) => x as i8 ,
151
- None => settings. log_levels . get ( "default" ) . unwrap ( ) . to_owned ( ) as i8 ,
185
+ Some ( & x) => x,
186
+ None => settings. log_levels . get ( "default" ) . unwrap ( ) . to_owned ( ) ,
152
187
} ;
153
- if log_level >= 0 {
154
- args. push ( format ! ( "--log-level={}" , log_level) ) ;
155
- }
188
+ args. push ( format ! ( "--log-level={}" , log_level) ) ;
156
189
157
190
args. push ( format ! ( "--buffer-size={}" , settings. client_buffer_size) ) ;
158
191
args. push ( format ! (
@@ -215,14 +248,14 @@ impl CondureService {
215
248
}
216
249
217
250
Self {
218
- service : Service :: new ( String :: from ( service_name) ) ,
251
+ service : Service :: new ( String :: from ( service_name) , log_level ) ,
219
252
args,
220
253
}
221
254
}
222
255
}
223
256
224
257
impl RunnerService for CondureService {
225
- fn start ( & mut self , sender : Sender < Result < ( ) , ServiceError > > ) -> Option < JoinHandle < ( ) > > {
258
+ fn start ( & mut self , sender : Sender < Result < ( ) , ServiceError > > ) -> Vec < Option < JoinHandle < ( ) > > > {
226
259
self . service . start ( self . args . clone ( ) , sender)
227
260
}
228
261
}
@@ -244,26 +277,24 @@ impl PushpinProxyService {
244
277
args. push ( format ! ( "--ipc-prefix={}" , settings. ipc_prefix) ) ;
245
278
}
246
279
let log_level = match settings. log_levels . get ( "pushpin-proxy" ) {
247
- Some ( & x) => x as i8 ,
248
- None => settings. log_levels . get ( "default" ) . unwrap ( ) . to_owned ( ) as i8 ,
280
+ Some ( & x) => x,
281
+ None => settings. log_levels . get ( "default" ) . unwrap ( ) . to_owned ( ) ,
249
282
} ;
250
- if log_level >= 0 {
251
- args. push ( format ! ( "--loglevel={}" , log_level) ) ;
252
- }
283
+ args. push ( format ! ( "--loglevel={}" , log_level) ) ;
253
284
254
285
for route in settings. route_lines . clone ( ) {
255
286
args. push ( format ! ( "--route={}" , route) ) ;
256
287
}
257
288
258
289
Self {
259
- service : Service :: new ( String :: from ( service_name) ) ,
290
+ service : Service :: new ( String :: from ( service_name) , log_level ) ,
260
291
args,
261
292
}
262
293
}
263
294
}
264
295
265
296
impl RunnerService for PushpinProxyService {
266
- fn start ( & mut self , sender : Sender < Result < ( ) , ServiceError > > ) -> Option < JoinHandle < ( ) > > {
297
+ fn start ( & mut self , sender : Sender < Result < ( ) , ServiceError > > ) -> Vec < Option < JoinHandle < ( ) > > > {
267
298
self . service . start ( self . args . clone ( ) , sender)
268
299
}
269
300
}
@@ -288,22 +319,75 @@ impl PushpinHandlerService {
288
319
args. push ( format ! ( "--ipc-prefix={}" , settings. ipc_prefix) ) ;
289
320
}
290
321
let log_level = match settings. log_levels . get ( "pushpin-handler" ) {
291
- Some ( & x) => x as i8 ,
292
- None => settings. log_levels . get ( "default" ) . unwrap ( ) . to_owned ( ) as i8 ,
322
+ Some ( & x) => x,
323
+ None => settings. log_levels . get ( "default" ) . unwrap ( ) . to_owned ( ) ,
293
324
} ;
294
- if log_level >= 0 {
295
- args. push ( format ! ( "--loglevel={}" , log_level) ) ;
296
- }
325
+ args. push ( format ! ( "--loglevel={}" , log_level) ) ;
297
326
298
327
Self {
299
- service : Service :: new ( String :: from ( service_name) ) ,
328
+ service : Service :: new ( String :: from ( service_name) , log_level ) ,
300
329
args,
301
330
}
302
331
}
303
332
}
304
333
305
334
impl RunnerService for PushpinHandlerService {
306
- fn start ( & mut self , sender : Sender < Result < ( ) , ServiceError > > ) -> Option < JoinHandle < ( ) > > {
335
+ fn start ( & mut self , sender : Sender < Result < ( ) , ServiceError > > ) -> Vec < Option < JoinHandle < ( ) > > > {
307
336
self . service . start ( self . args . clone ( ) , sender)
308
337
}
309
338
}
339
+
340
+ fn start_log_handler (
341
+ stdout : ChildStdout ,
342
+ stderr : ChildStderr ,
343
+ name : String ,
344
+ ) -> Vec < Option < JoinHandle < ( ) > > > {
345
+ let mut result: Vec < Option < JoinHandle < ( ) > > > = Vec :: new ( ) ;
346
+
347
+ let name_str = name. clone ( ) ;
348
+ result. push ( Some ( thread:: spawn ( move || {
349
+ let reader = BufReader :: new ( stdout) ;
350
+ for line in reader. lines ( ) {
351
+ match line {
352
+ Ok ( msg) => log_message ( & name_str, log:: Level :: Info , & msg) ,
353
+ Err ( _) => {
354
+ log_message (
355
+ & name_str,
356
+ log:: Level :: Error ,
357
+ "failed to read from standard out." ,
358
+ ) ;
359
+ break ;
360
+ }
361
+ }
362
+ }
363
+ } ) ) ) ;
364
+
365
+ result. push ( Some ( thread:: spawn ( move || {
366
+ let reader_err = BufReader :: new ( stderr) ;
367
+ for line in reader_err. lines ( ) {
368
+ match line {
369
+ Ok ( msg) => log_message ( & name, log:: Level :: Error , & msg) ,
370
+ Err ( _) => {
371
+ log_message (
372
+ & name,
373
+ log:: Level :: Error ,
374
+ "failed to read from standard error." ,
375
+ ) ;
376
+ break ;
377
+ }
378
+ }
379
+ }
380
+ } ) ) ) ;
381
+
382
+ result
383
+ }
384
+
385
+ fn log_message ( name : & str , level : log:: Level , msg : & str ) {
386
+ log:: logger ( ) . log (
387
+ & log:: Record :: builder ( )
388
+ . level ( level)
389
+ . target ( name)
390
+ . args ( format_args ! ( "{}" , msg) )
391
+ . build ( ) ,
392
+ ) ;
393
+ }
0 commit comments