blob: 9acc1fdd51e169b78b9d2c9abba2163143bd6ee5 [file] [log] [blame]
mod actors;
mod analytics;
mod args;
mod benchmarks;
mod plot;
mod rate_limiter;
mod runner;
mod utils;
use crate::{args::common::IggyBenchArgs, runner::BenchmarkRunner};
use clap::Parser;
use figlet_rs::FIGfont;
use hostname::get;
use iggy::error::IggyError;
use std::fs;
use std::path::Path;
use tracing::{error, info};
use tracing_subscriber::{fmt, layer::SubscriberExt, util::SubscriberInitExt, EnvFilter};
use utils::copy_directory_contents;
#[tokio::main]
async fn main() -> Result<(), IggyError> {
let standard_font = FIGfont::standard().unwrap();
let figure = standard_font.convert("Iggy Bench");
println!("{}", figure.unwrap());
let args = IggyBenchArgs::parse();
args.validate();
// Set default identifier as hostname if not provided
if args.identifier().is_none() {
info!(
"Using hostname: {} as identifier",
get().unwrap().to_string_lossy()
);
} else {
info!("Using identifier: {}", args.identifier().unwrap());
}
// Store output_dir before moving args
let output_dir = args.output_dir();
let benchmark_dir = output_dir.as_ref().map(|dir| {
let dir_path = Path::new(dir);
if !dir_path.exists() {
fs::create_dir_all(dir_path).unwrap();
}
dir_path.join(args.generate_dir_name())
});
// Configure logging
let env_filter = EnvFilter::try_from_default_env().unwrap_or(EnvFilter::new("INFO"));
let stdout_layer = fmt::layer().with_ansi(true);
// If output directory is specified, also log to file
if let Some(ref benchmark_dir) = benchmark_dir {
// Create output directory if it doesn't exist
fs::create_dir_all(benchmark_dir).unwrap();
let file_appender = tracing_appender::rolling::never(benchmark_dir, "bench.log");
let file_layer = fmt::layer().with_ansi(false).with_writer(file_appender);
tracing_subscriber::registry()
.with(env_filter)
.with(stdout_layer)
.with(file_layer)
.init();
} else {
tracing_subscriber::registry()
.with(env_filter)
.with(stdout_layer)
.init();
}
let mut benchmark_runner = BenchmarkRunner::new(args);
// Store server address before running benchmark since args will be taken
let server_addr = benchmark_runner
.args
.as_ref()
.unwrap()
.server_address()
.to_string();
info!("Starting the benchmarks...");
let ctrl_c = tokio::signal::ctrl_c();
let benchmark_future = benchmark_runner.run();
tokio::select! {
_ = ctrl_c => {
info!("Received Ctrl-C, exiting...");
// Clean up unfinished benchmark directory on manual interruption
if let Some(ref benchmark_dir) = benchmark_dir {
info!("Cleaning up unfinished benchmark directory...");
if let Err(e) = std::fs::remove_dir_all(benchmark_dir) {
error!("Failed to clean up benchmark directory: {}", e);
}
}
}
result = benchmark_future => {
if let Err(e) = result {
error!("Benchmark failed with error: {:?}", e);
return Err(e);
}
// Copy server logs and config if output directory is specified and
// (server was started by benchmark OR (running on localhost and local_data exists))
if let Some(ref benchmark_dir) = benchmark_dir {
let is_localhost = server_addr
.split(':')
.next()
.map(|host| host == "localhost" || host == "127.0.0.1")
.unwrap_or(false);
let local_data = Path::new("local_data");
let should_copy = benchmark_runner.test_server.is_some() ||
(is_localhost && local_data.exists());
if should_copy {
// Copy server logs
let logs_dir = local_data.join("logs");
if logs_dir.exists() {
if let Err(e) = copy_directory_contents(&logs_dir, benchmark_dir) {
error!("Failed to copy server logs: {}", e);
}
}
// Copy server config
let runtime_dir = local_data.join("runtime");
if runtime_dir.exists() {
if let Err(e) = copy_directory_contents(&runtime_dir, benchmark_dir) {
error!("Failed to copy server configuration: {}", e);
}
}
}
}
}
}
Ok(())
}