diff --git a/cargo-shuttle/src/args.rs b/cargo-shuttle/src/args.rs index 6667e0bd8..adf4cc519 100644 --- a/cargo-shuttle/src/args.rs +++ b/cargo-shuttle/src/args.rs @@ -14,7 +14,6 @@ use clap::{ use clap_complete::Shell; use shuttle_common::constants::{DEFAULT_IDLE_MINUTES, EXAMPLES_REPO}; use shuttle_common::resource; -use uuid::Uuid; #[derive(Parser)] #[command( @@ -411,7 +410,7 @@ impl InitTemplateArg { #[derive(Parser, Clone, Debug, Default)] pub struct LogsArgs { /// Deployment ID to get logs for. Defaults to currently running deployment - pub id: Option, + pub id: Option, #[arg(short, long)] /// View logs from the most recent deployment (which is not always the latest running one) pub latest: bool, @@ -430,6 +429,9 @@ pub struct LogsArgs { /// View all log lines #[arg(long, group = "output_mode")] pub all: bool, + /// Get logs from all deployments instead of one deployment + #[arg(long)] + pub all_deployments: bool, } /// Helper function to parse and return the absolute path diff --git a/cargo-shuttle/src/client.rs b/cargo-shuttle/src/client.rs index 64016f998..23880e419 100644 --- a/cargo-shuttle/src/client.rs +++ b/cargo-shuttle/src/client.rs @@ -8,7 +8,7 @@ use reqwest::header::HeaderMap; use reqwest::{RequestBuilder, Response}; use serde::{Deserialize, Serialize}; use shuttle_common::constants::headers::X_CARGO_SHUTTLE_VERSION; -use shuttle_common::log::LogsRange; +use shuttle_common::log::{LogsRange, LogsResponseBeta}; use shuttle_common::models::deployment::{DeploymentRequest, DeploymentRequestBeta}; use shuttle_common::models::team; use shuttle_common::models::{deployment, project, service, ToJson}; @@ -250,7 +250,7 @@ impl ShuttleApiClient { pub async fn get_logs( &self, project: &str, - deployment_id: &Uuid, + deployment_id: &str, range: LogsRange, ) -> Result> { let mut path = format!("/projects/{project}/deployments/{deployment_id}/logs"); @@ -260,11 +260,25 @@ impl ShuttleApiClient { .await .context("Failed parsing logs. Is your cargo-shuttle outdated?") } + pub async fn get_deployment_logs_beta( + &self, + project: &str, + deployment_id: &str, + ) -> Result { + let path = format!("/projects/{project}/deployments/{deployment_id}/logs"); + + self.get(path).await.context("Failed parsing logs.") + } + pub async fn get_project_logs_beta(&self, project: &str) -> Result { + let path = format!("/projects/{project}/logs"); + + self.get(path).await.context("Failed parsing logs.") + } pub async fn get_logs_ws( &self, project: &str, - deployment_id: &Uuid, + deployment_id: &str, range: LogsRange, ) -> Result>> { let mut path = format!("/projects/{project}/ws/deployments/{deployment_id}/logs"); @@ -287,12 +301,6 @@ impl ShuttleApiClient { }; } - pub async fn deployments_beta(&self, project: &str) -> Result> { - let path = format!("/projects/{project}/deployments",); - - self.get(path).await - } - pub async fn get_deployments( &self, project: &str, @@ -307,6 +315,22 @@ impl ShuttleApiClient { self.get(path).await } + pub async fn get_deployments_beta( + &self, + project: &str, + ) -> Result> { + let path = format!("/projects/{project}/deployments"); + + self.get(path).await + } + pub async fn _get_current_deployment_beta( + &self, + project: &str, + ) -> Result { + let path = format!("/projects/{project}/deployments/current"); + + self.get(path).await + } pub async fn deployment_status( &self, diff --git a/cargo-shuttle/src/lib.rs b/cargo-shuttle/src/lib.rs index f7414ee17..ba8e21fb4 100644 --- a/cargo-shuttle/src/lib.rs +++ b/cargo-shuttle/src/lib.rs @@ -850,31 +850,23 @@ impl Shuttle { async fn logs_beta(&self, args: LogsArgs) -> Result { let client = self.client.as_ref().unwrap(); - let mut stream = client - // TODO: use something else than a fake Uuid - .get_logs_ws(self.ctx.project_name(), &Uuid::new_v4(), LogsRange::All) - .await - .map_err(|err| { - suggestions::logs::get_logs_failure(err, "Connecting to the logs stream failed") - })?; - - while let Some(Ok(msg)) = stream.next().await { - if let tokio_tungstenite::tungstenite::Message::Text(line) = msg { - match serde_json::from_str::(&line) { - Ok(log) => { - if args.raw { - println!("{}", log.line); - } else { - println!("{log}"); - } - } - Err(err) => { - // TODO better handle logs, by returning a different type than the log line - // if an error happened. - bail!(err); - } - } - } + let proj_name = self.ctx.project_name(); + let logs = if args.all_deployments { + client.get_project_logs_beta(proj_name).await?.logs + } else { + // TODO: + // let depl = client.get_current_deployment_beta(proj_name).await?; + let depls = client.get_deployments_beta(proj_name).await?; + let depl = depls + .first() + .expect("at least one deployment in this project"); + client + .get_deployment_logs_beta(proj_name, &depl.id) + .await? + .logs + }; + for log in logs { + println!("{}", log); } Ok(CommandOutcome::Ok) @@ -908,10 +900,10 @@ impl Shuttle { "Could not find any deployments for '{proj_name}'. Try passing a deployment ID manually", ))?; - most_recent.id + most_recent.id.to_string() } else if let Some(deployment) = client.get_service(proj_name).await?.deployment { // Active deployment - deployment.id + deployment.id.to_string() } else { bail!( "Could not find a running deployment for '{proj_name}'. \ @@ -984,7 +976,7 @@ impl Shuttle { let deployments_len = if self.beta { let deployments = client - .deployments_beta(proj_name) + .get_deployments_beta(proj_name) .await .map_err(suggestions::deployment::get_deployments_list_failure)?; let table = deployments_table_beta(&deployments, proj_name, raw); @@ -1862,7 +1854,11 @@ impl Shuttle { .map_err(suggestions::deploy::deploy_request_failure)?; let mut stream = client - .get_logs_ws(self.ctx.project_name(), &deployment.id, LogsRange::All) + .get_logs_ws( + self.ctx.project_name(), + &deployment.id.to_string(), + LogsRange::All, + ) .await .map_err(|err| { suggestions::deploy::deployment_setup_failure( @@ -1982,7 +1978,11 @@ impl Shuttle { // the terminal isn't completely spammed sleep(Duration::from_millis(100)).await; stream = client - .get_logs_ws(self.ctx.project_name(), &deployment.id, LogsRange::All) + .get_logs_ws( + self.ctx.project_name(), + &deployment.id.to_string(), + LogsRange::All, + ) .await .map_err(|err| { suggestions::deploy::deployment_setup_failure( diff --git a/common/src/log.rs b/common/src/log.rs index 691c40cc7..1bdfde2d6 100644 --- a/common/src/log.rs +++ b/common/src/log.rs @@ -94,6 +94,11 @@ impl std::fmt::Display for LogItemBeta { } } +#[derive(Debug, Serialize, Deserialize)] +pub struct LogsResponseBeta { + pub logs: Vec, +} + const LOGLINE_MAX_CHARS: usize = 2048; const TRUNC_MSG: &str = "... (truncated)";