use lobe_core::engine::history::RegressionSummary;
use lobe_core::models::{ProbeResult, ProbeStatus, TlsStatus};
pub fn print_probe_result(result: &ProbeResult) {
println!("Run #{}", result.id);
println!("target: {}", result.target);
println!("status: {}", format_status(result.status));
println!(
"timing: dns={}ms tcp={}ms tls={}ms ttfb={}ms download={}ms total={}ms",
result.report.dns_ms,
result.report.tcp_ms,
result.report.tls_ms,
result.report.ttfb_ms,
result.report.download_ms,
result.report.total_ms
);
if let Some(tls) = &result.tls {
println!(
"tls: {}{}{}",
format_tls_status(tls.status),
tls.version
.as_deref()
.map(|value| format!(" version={value}"))
.unwrap_or_default(),
tls.cipher_suite
.as_deref()
.map(|value| format!(" cipher={value}"))
.unwrap_or_default()
);
}
if let Some(error_message) = &result.error_message {
println!("error: {error_message}");
}
}
pub fn print_history(results: &[ProbeResult]) {
if results.is_empty() {
println!("No saved runs found.");
return;
}
for result in results {
println!(
"#{} [{}] {} total={}ms ttfb={}ms created_at_ms={}",
result.id,
format_status(result.status),
result.target,
result.report.total_ms,
result.report.ttfb_ms,
result.created_at_ms
);
}
}
pub fn print_comparison(current: &ProbeResult, previous: &ProbeResult, summary: &RegressionSummary) {
println!("target: {}", current.target);
println!(
"current: run #{} total={}ms ttfb={}ms",
current.id, current.report.total_ms, current.report.ttfb_ms
);
println!(
"previous: run #{} total={}ms ttfb={}ms",
previous.id, previous.report.total_ms, previous.report.ttfb_ms
);
println!(
"delta: {}ms ({:.1}%) threshold={:.1}% status={}",
summary.delta_ms,
summary.delta_percent,
summary.threshold_percent,
if summary.exceeded_threshold {
"regression"
} else {
"within-threshold"
}
);
}
pub fn print_comparison_unavailable(target: &str) {
println!("Not enough saved runs to compare for target: {target}");
}
pub fn print_zero_baseline_notice(target: &str) {
println!("Cannot compare target {target} because the previous run had 0ms TTFB.");
}
pub fn print_watch_result(
result: &ProbeResult,
comparison: Option<&RegressionSummary>,
comparison_note: Option<&str>,
) {
print!(
"#{} [{}] total={}ms ttfb={}ms download={}ms dns={}ms tcp={}ms tls={}ms",
result.id,
format_status(result.status),
result.report.total_ms,
result.report.ttfb_ms,
result.report.download_ms,
result.report.dns_ms,
result.report.tcp_ms,
result.report.tls_ms
);
if let Some(tls) = &result.tls {
print!(" tls_status={}", format_tls_status(tls.status));
}
if let Some(summary) = comparison {
print!(
" delta_ttfb={}ms ({:.1}%) {}",
summary.delta_ms,
summary.delta_percent,
if summary.exceeded_threshold {
"REGRESSION"
} else {
"ok"
}
);
}
if let Some(note) = comparison_note {
print!(" note={note}");
}
if let Some(error_message) = &result.error_message {
print!(" error={error_message}");
}
println!();
}
fn format_status(status: ProbeStatus) -> &'static str {
match status {
ProbeStatus::Succeeded => "succeeded",
ProbeStatus::Failed => "failed",
}
}
fn format_tls_status(status: TlsStatus) -> &'static str {
match status {
TlsStatus::NotUsed => "not-used",
TlsStatus::HandshakeSucceeded => "handshake-succeeded",
TlsStatus::HandshakeFailed => "handshake-failed",
}
}