use super::funejson::Value; use super::math_round_div::round_div; /// HTTP status codes counted by class, with the server error rate (5xx) and /// the client error rate (4xx) kept apart: only 5xx is the server's failure. /// /// # Panics /// Panics on a status code outside 100 to 599. pub fn summarise_status_codes(statuses: &[i64]) -> StatusCodeSummary { let mut counts = [0i64; 5]; for &s in statuses { if !(100..=599).contains(&s) { panic!("status code must be 100 to 599, received {}", s); } counts[(s / 100 - 1) as usize] += 1; } let total = statuses.len() as i64; let rate = |n: i64| if total == 0 { 0 } else { round_div(n * 10000, total, "half-up") }; StatusCodeSummary { total, informational: counts[0], success: counts[1], redirect: counts[2], client_error: counts[3], server_error: counts[4], error_rate_basis_points: rate(counts[4]), client_error_rate_basis_points: rate(counts[3]), } } pub fn status_code_summary_to_value(s: &StatusCodeSummary) -> Value { Value::obj(vec![ ("total", Value::Int(s.total)), ("informational", Value::Int(s.informational)), ("success", Value::Int(s.success)), ("redirect", Value::Int(s.redirect)), ("clientError", Value::Int(s.client_error)), ("serverError", Value::Int(s.server_error)), ("errorRateBasisPoints", Value::Int(s.error_rate_basis_points)), ("clientErrorRateBasisPoints", Value::Int(s.client_error_rate_basis_points)), ]) } pub fn fune_vector(args: &[Value]) -> Value { let statuses: Vec = args[0] .as_arr() .iter() .map(|v| match v { Value::Int(i) => *i, _ => panic!("status code must be a whole number"), }) .collect(); status_code_summary_to_value(&summarise_status_codes(&statuses)) }