@@ -12,7 +12,9 @@ use crate::{
1212use async_trait;
1313use bollard:: {
1414 Docker ,
15- container:: { RemoveContainerOptions , StartContainerOptions , WaitContainerOptions } ,
15+ container:: {
16+ LogOutput , LogsOptions , RemoveContainerOptions , StartContainerOptions , WaitContainerOptions ,
17+ } ,
1618 errors:: Error :: DockerContainerWaitError ,
1719 image:: { CreateImageOptions , ImportImageOptions } ,
1820} ;
@@ -70,6 +72,9 @@ impl Orchestrator for LocalDockerOrchestrator {
7072 ) -> Result < PodResult > {
7173 ASYNC_RUNTIME . block_on ( self . get_result ( pod_run, namespace_lookup) )
7274 }
75+ fn get_logs_blocking ( & self , pod_run : & PodRun ) -> Result < String > {
76+ ASYNC_RUNTIME . block_on ( self . get_logs ( pod_run) )
77+ }
7378 #[ expect(
7479 clippy:: try_err,
7580 reason = r#"
@@ -263,8 +268,65 @@ impl Orchestrator for LocalDockerOrchestrator {
263268 ) ,
264269 } ) ?,
265270 namespace_lookup,
271+ self . get_logs ( pod_run) . await ?,
266272 )
267273 }
274+
275+ async fn get_logs ( & self , pod_run : & PodRun ) -> Result < String > {
276+ let mut std_out = Vec :: new ( ) ;
277+ let mut std_err = Vec :: new ( ) ;
278+
279+ self . api
280+ . logs :: < String > (
281+ & pod_run. assigned_name ,
282+ Some ( LogsOptions {
283+ stdout : true ,
284+ stderr : true ,
285+ ..Default :: default ( )
286+ } ) ,
287+ )
288+ . try_collect :: < Vec < _ > > ( )
289+ . await ?
290+ . iter ( )
291+ . for_each ( |log_output| match log_output {
292+ LogOutput :: StdOut { message } => {
293+ std_out. extend ( message. to_vec ( ) ) ;
294+ }
295+ LogOutput :: StdErr { message } => {
296+ std_err. extend ( message. to_vec ( ) ) ;
297+ }
298+ LogOutput :: StdIn { .. } | LogOutput :: Console { .. } => {
299+ // Ignore stdin logs, as they are not relevant for our use case
300+ }
301+ } ) ;
302+
303+ let mut logs = String :: from_utf8_lossy ( & std_out) . to_string ( ) ;
304+ if !std_err. is_empty ( ) {
305+ logs. push_str ( "\n STDERR:\n " ) ;
306+ logs. push_str ( & String :: from_utf8_lossy ( & std_err) ) ;
307+ }
308+
309+ // Check for errors in the docker state, if exist, attach it to logs
310+ // This is for when the container exits immediately due to a bad command or similar
311+ let error = self
312+ . api
313+ . inspect_container ( & pod_run. assigned_name , None )
314+ . await ?
315+ . state
316+ . context ( selector:: FailedToExtractRunInfo {
317+ container_name : & pod_run. assigned_name ,
318+ } ) ?
319+ . error
320+ . context ( selector:: FailedToExtractRunInfo {
321+ container_name : & pod_run. assigned_name ,
322+ } ) ?;
323+
324+ if !error. is_empty ( ) {
325+ logs. push_str ( & error) ;
326+ }
327+
328+ Ok ( logs)
329+ }
268330}
269331
270332#[ uniffi:: export]
0 commit comments