use std::time::Duration;
use crate::client;
use crate::config::ProjectConfig;
#[derive(Debug, thiserror::Error)]
pub enum Error {
#[error(transparent)]
Client(#[from] crate::client::ClientError),
#[error(transparent)]
Json(#[from] serde_json::Error),
}
type Result<T> = std::result::Result<T, Error>;
#[derive(Debug, clap::Args)]
pub struct LogsArgs {
#[arg(long, env = "BOATRAMP_SERVER", global = true)]
server: Option<String>,
#[arg(long, env = "BOATRAMP_SITE", global = true)]
site: Option<String>,
#[arg(long)]
stream: Option<String>,
#[arg(long, default_value_t = 200)]
limit: usize,
#[arg(long, short)]
follow: bool,
}
pub async fn run(args: LogsArgs, config: &ProjectConfig) -> Result<()> {
let (server, site) = client::resolve_target(args.server, args.site, config)?;
let cp = client::ControlPlane::new(
server,
client::http_client(client::token(config).as_deref()),
client::resolve_project(config),
);
let stream = args.stream.as_deref();
let first = cp.fetch_logs(&site, args.limit, 0, stream).await?;
let mut cursor = first.entries.last().map(|e| e.seq).unwrap_or(0);
for entry in &first.entries {
print_line(entry);
}
if first.dropped > 0 {
eprintln!(
"(\u{2026} {} line(s) dropped by the rate cap)",
first.dropped
);
}
if !args.follow {
return Ok(());
}
loop {
tokio::time::sleep(Duration::from_secs(1)).await;
let next = cp
.fetch_logs(&site, args.limit.max(1000), cursor, stream)
.await?;
for entry in &next.entries {
print_line(entry);
cursor = cursor.max(entry.seq);
}
}
}
fn print_line(entry: &client::LogEntry) {
println!("[{}] {}", entry.stream, entry.line);
}
#[derive(Debug, clap::Args)]
pub struct StatsArgs {
#[arg(long, env = "BOATRAMP_SERVER", global = true)]
server: Option<String>,
#[arg(long, env = "BOATRAMP_SITE", global = true)]
site: Option<String>,
}
pub async fn stats(args: StatsArgs, config: &ProjectConfig) -> Result<()> {
let (server, site) = client::resolve_target(args.server, args.site, config)?;
let cp = client::ControlPlane::new(
server,
client::http_client(client::token(config).as_deref()),
client::resolve_project(config),
);
let stats = cp.fetch_handler_stats(&site).await?;
println!("{}", serde_json::to_string_pretty(&stats)?);
Ok(())
}