Repository: shuttle-hq/shuttle (Rust)

Issue:
[Improvement]: Add the `--raw` flag to the `run` and `deploy` commands
Currently, the `logs` command has a `--raw` flag that disables the printing of timestamps and origins of log lines:
https://github.com/shuttle-hq/shuttle/blob/c5f2caf037eb5ce05dda80dcd01ba8618319d3be/cargo-shuttle/src/lib.rs#L815-L821

The suggestion is to add this to the local run and deploy commands as well, to that the same behavior is seen when they print their logs.


---

<sub>This issue is open to contribution. Comment if you want to work on it. Feel free to ask for help and guidance here or in our Discord.</sub>


Discussion: I would like to try this issue.
This is a bit of a different discussion, but I think it would be nice to be able to output the log format in json. (Sorry, this is probably not the right place to discuss this.)
Not a bad idea! The logs request returns the logs in JSON format, so it should be very simple to add that as well. Feel free to try and see what you come up with!



Fix (patch):
diff --git a/cargo-shuttle/src/args.rs b/cargo-shuttle/src/args.rs
index c571b5d7e1..e0f15a8ac2 100644
--- a/cargo-shuttle/src/args.rs
+++ b/cargo-shuttle/src/args.rs
@@ -108,19 +108,7 @@ pub enum Command {
     /// Stop this Shuttle service
     Stop,
     /// View the logs of a deployment in this Shuttle service
-    Logs {
-        /// Deployment ID to get logs for. Defaults to currently running deployment
-        id: Option<Uuid>,
-        #[arg(short, long)]
-        /// View logs from the most recent deployment (which is not always the latest running one)
-        latest: bool,
-        #[arg(short, long)]
-        /// Follow log output
-        follow: bool,
-        #[arg(long)]
-        /// Don't display timestamps and log origin tags
-        raw: bool,
-    },
+    Logs(LogsArgs),
     /// List or manage projects on Shuttle
     #[command(subcommand)]
     Project(ProjectCommand),
@@ -271,6 +259,9 @@ pub struct DeployArgs {
     /// Don't run pre-deploy tests
     #[arg(long, visible_alias = "nt")]
     pub no_test: bool,
+    /// Don't display timestamps and log origin tags
+    #[arg(long)]
+    pub raw: bool,
 
     #[command(flatten)]
     pub secret_args: SecretsArgs,
@@ -287,6 +278,9 @@ pub struct RunArgs {
     /// Use release mode for building the project
     #[arg(long, short = 'r')]
     pub release: bool,
+    /// Don't display timestamps and log origin tags
+    #[arg(long)]
+    pub raw: bool,
 
     #[command(flatten)]
     pub secret_args: SecretsArgs,
@@ -407,6 +401,21 @@ impl InitTemplateArg {
     }
 }
 
+#[derive(Parser, Clone, Debug, Default)]
+pub struct LogsArgs {
+    /// Deployment ID to get logs for. Defaults to currently running deployment
+    pub id: Option<Uuid>,
+    #[arg(short, long)]
+    /// View logs from the most recent deployment (which is not always the latest running one)
+    pub latest: bool,
+    #[arg(short, long)]
+    /// Follow log output
+    pub follow: bool,
+    /// Don't display timestamps and log origin tags
+    #[arg(long)]
+    pub raw: bool,
+}
+
 /// Helper function to parse and return the absolute path
 fn parse_path(path: OsString) -> Result<PathBuf, io::Error> {
     dunce::canonicalize(&path).map_err(|e| {
diff --git a/cargo-shuttle/src/lib.rs b/cargo-shuttle/src/lib.rs
index eca66eb3dc..53963f7305 100644
--- a/cargo-shuttle/src/lib.rs
+++ b/cargo-shuttle/src/lib.rs
@@ -72,7 +72,7 @@ use uuid::Uuid;
 
 pub use crate::args::{Command, ProjectArgs, RunArgs, ShuttleArgs};
 use crate::args::{
-    DeployArgs, DeploymentCommand, InitArgs, LoginArgs, LogoutArgs, ProjectCommand,
+    DeployArgs, DeploymentCommand, InitArgs, LoginArgs, LogoutArgs, LogsArgs, ProjectCommand,
     ProjectStartArgs, ResourceCommand, TemplateLocation,
 };
 use crate::client::Client;
@@ -222,12 +222,7 @@ impl Shuttle {
             Command::Run(run_args) => self.local_run(run_args).await,
             Command::Deploy(deploy_args) => self.deploy(deploy_args).await,
             Command::Status => self.status().await,
-            Command::Logs {
-                id,
-                latest,
-                follow,
-                raw,
-            } => self.logs(id, latest, follow, raw).await,
+            Command::Logs(logs_args) => self.logs(logs_args).await,
             Command::Deployment(DeploymentCommand::List { page, limit, raw }) => {
                 self.deployments_list(page, limit, raw).await
             }
@@ -843,20 +838,14 @@ impl Shuttle {
         Ok(CommandOutcome::Ok)
     }
 
-    async fn logs(
-        &self,
-        id: Option<Uuid>,
-        latest: bool,
-        follow: bool,
-        raw: bool,
-    ) -> Result<CommandOutcome> {
+    async fn logs(&self, args: LogsArgs) -> Result<CommandOutcome> {
         let client = self.client.as_ref().unwrap();
-        let id = if let Some(id) = id {
+        let id = if let Some(id) = args.id {
             id
         } else {
             let proj_name = self.ctx.project_name();
 
-            if latest {
+            if args.latest {
                 // Find latest deployment (not always an active one)
                 let deployments = client
                     .get_deployments(proj_name, 0, 1)
@@ -883,7 +872,7 @@ impl Shuttle {
             }
         };
 
-        if follow {
+        if args.follow {
             let mut stream = client
                 .get_logs_ws(self.ctx.project_name(), &id)
                 .await
@@ -895,10 +884,10 @@ impl Shuttle {
                 if let tokio_tungstenite::tungstenite::Message::Text(line) = msg {
                     match serde_json::from_str::<shuttle_common::LogItem>(&line) {
                         Ok(log) => {
-                            if raw {
-                                println!("{}", log.get_raw_line());
+                            if args.raw {
+                                println!("{}", log.get_raw_line())
                             } else {
-                                println!("{log}");
+                                println!("{log}")
                             }
                         }
                         Err(err) => {
@@ -924,10 +913,10 @@ impl Shuttle {
                 })?;
 
             for log in logs.into_iter() {
-                if raw {
-                    println!("{}", log.get_raw_line());
+                if args.raw {
+                    println!("{}", log.get_raw_line())
                 } else {
-                    println!("{log}");
+                    println!("{log}")
                 }
             }
         }
@@ -1117,6 +1106,7 @@ impl Shuttle {
             .context("child process did not have a handle to stdout")?;
         let mut reader = BufReader::new(child_stdout).lines();
         let service_name_clone = service_name.clone();
+        let raw = run_args.raw;
         tokio::spawn(async move {
             while let Some(line) = reader.next_line().await.unwrap() {
                 let log_item = LogItem::new(
@@ -1124,7 +1114,12 @@ impl Shuttle {
                     shuttle_common::log::Backend::Runtime(service_name_clone.clone()),
                     line,
                 );
-                println!("{log_item}");
+
+                if raw {
+                    println!("{}", log_item.get_raw_line())
+                } else {
+                    println!("{log_item}")
+                }
             }
         });
 
@@ -1717,7 +1712,11 @@ impl Shuttle {
                         }
                     };
 
-                    println!("{log_item}");
+                    if args.raw {
+                        println!("{}", log_item.get_raw_line())
+                    } else {
+                        println!("{log_item}")
+                    }
 
                     // Detect versions of deployer and runtime, and print warnings of outdated.
                     if !deployer_version_checked