use anyhow::{Context, Result};
use clap::Parser;
use std::io::{BufRead, BufReader};
use std::path::PathBuf;
use std::time::Duration;
use tracing_durations_export::plot::{plot, OwnedSpanInfo, PlotConfig, PlotLayout};
#[derive(Parser, Debug)]
#[command(author, version, about, long_about = None)]
struct Args {
input: PathBuf,
#[clap(long)]
output: Option<PathBuf>,
#[clap(long)]
multi_lane: bool,
#[clap(long)]
min_length: Option<f32>,
#[clap(long)]
inline_field: bool,
#[clap(long)]
remove: Option<Vec<String>>,
#[clap(long, default_value_t = PlotConfig::default().color_top_blocking)]
color_top_blocking: String,
#[clap(long, default_value_t = PlotConfig::default().color_top_threadpool)]
color_top_threadpool: String,
#[clap(long, default_value_t = PlotConfig::default().color_bottom)]
color_bottom: String,
#[clap(long)]
skip_top: bool,
#[clap(long)]
skip_bottom: bool,
}
fn main() -> Result<()> {
let args: Args = Args::parse();
let reader = BufReader::new(fs::File::open(&args.input)?);
let spans: Vec<OwnedSpanInfo> = reader
.lines()
.map(|line| {
let string = line.context("Failed to read line from input file")?;
serde_json::from_str(&string).context("Invalid line in input file")
})
.collect::<Result<_>>()?;
let end = spans
.iter()
.map(|span| span.end)
.max()
.context("Input file is empty")?;
let plot_config = PlotConfig {
multi_lane: args.multi_lane,
min_length: args.min_length.map(Duration::from_secs_f32),
remove: args.remove.map(|remove| remove.into_iter().collect()),
inline_field: args.inline_field,
color_top_blocking: args.color_top_blocking,
color_top_threadpool: args.color_top_threadpool,
color_bottom: args.color_bottom,
skip_top: args.skip_top,
skip_bottom: args.skip_bottom,
};
let document = plot(&spans, end, &plot_config, &PlotLayout::default());
let svg = args.output.unwrap_or(args.input.with_extension("svg"));
svg::save(svg, &document).context("Failed to write svg")?;
Ok(())
}