This commit is contained in:
Mateusz Gruszczyński committed 2026-10-05 09:30:21 +02:00
1 parent 1dea7f55c8
commit c819f0a335
151 files changed
+7610 -4264

No files matched your search

+99 -24
View File
@@ -169,7 +169,10 @@ struct LiveLogFilters {
}
fn log_string<'a>(entry: &'a serde_json::Value, key: &str) -> &'a str {
entry.get(key).and_then(|value| value.as_str()).unwrap_or("-")
entry
.get(key)
.and_then(|value| value.as_str())
.unwrap_or("-")
}
fn log_optional_string<'a>(entry: &'a serde_json::Value, key: &str) -> Option<&'a str> {
@@ -178,7 +181,10 @@ fn log_optional_string<'a>(entry: &'a serde_json::Value, key: &str) -> Option<&'
fn live_status_matches(filter: &str, status: u64) -> bool {
if let Some(prefix) = filter.strip_suffix("xx") {
return prefix.parse::<u64>().ok().is_some_and(|class| status / 100 == class);
return prefix
.parse::<u64>()
.ok()
.is_some_and(|class| status / 100 == class);
}
filter.parse::<u64>().ok() == Some(status)
}
@@ -205,7 +211,10 @@ fn live_log_matches(entry: &serde_json::Value, filters: &LiveLogFilters) -> bool
return false;
}
}
let status = entry.get("status").and_then(|value| value.as_u64()).unwrap_or(0);
let status = entry
.get("status")
.and_then(|value| value.as_u64())
.unwrap_or(0);
if filters
.status
.as_ref()
@@ -234,7 +243,10 @@ fn live_log_matches(entry: &serde_json::Value, filters: &LiveLogFilters) -> bool
}
fn live_time(entry: &serde_json::Value) -> String {
let ms = entry.get("time_ms").and_then(|value| value.as_u64()).unwrap_or(0);
let ms = entry
.get("time_ms")
.and_then(|value| value.as_u64())
.unwrap_or(0);
let seconds = (ms / 1000) % 86_400;
format!(
"{:02}:{:02}:{:02}.{:03}Z",
@@ -246,8 +258,14 @@ fn live_time(entry: &serde_json::Value) -> String {
}
fn print_live_entry(entry: &serde_json::Value, detail: bool) {
let id = entry.get("id").and_then(|value| value.as_u64()).unwrap_or(0);
let status = entry.get("status").and_then(|value| value.as_u64()).unwrap_or(0);
let id = entry
.get("id")
.and_then(|value| value.as_u64())
.unwrap_or(0);
let status = entry
.get("status")
.and_then(|value| value.as_u64())
.unwrap_or(0);
let duration = entry
.get("duration_ms")
.and_then(|value| value.as_u64())
@@ -304,7 +322,9 @@ fn live_filters_summary(filters: &LiveLogFilters) -> String {
let mut values = Vec::new();
macro_rules! add {
($name:literal, $value:expr) => {
if let Some(value) = $value.as_ref() { values.push(format!("{}={}", $name, value)); }
if let Some(value) = $value.as_ref() {
values.push(format!("{}={}", $name, value));
}
};
}
add!("host", filters.host);
@@ -317,11 +337,23 @@ fn live_filters_summary(filters: &LiveLogFilters) -> String {
add!("cache", filters.cache);
add!("status", filters.status);
add!("path", filters.path_prefix);
if filters.errors_only { values.push("errors=on".into()); }
if let Some(ms) = filters.slow_ms { values.push(format!("slow>={ms}ms")); }
if filters.detail { values.push("detail=on".into()); }
if filters.paused { values.push("paused".into()); }
if values.is_empty() { "none".into() } else { values.join(" ") }
if filters.errors_only {
values.push("errors=on".into());
}
if let Some(ms) = filters.slow_ms {
values.push(format!("slow>={ms}ms"));
}
if filters.detail {
values.push("detail=on".into());
}
if filters.paused {
values.push("paused".into());
}
if values.is_empty() {
"none".into()
} else {
values.join(" ")
}
}
fn live_help() {
@@ -356,20 +388,44 @@ fn handle_live_command(
match command.as_str() {
"help" | "?" => live_help(),
"filters" => println!("filters: {}", live_filters_summary(filters)),
"reset" => { *filters = LiveLogFilters::default(); println!("filters cleared"); }
"pause" => { filters.paused = true; println!("paused"); }
"resume" => { filters.paused = false; println!("resumed"); }
"clear" => { print!("\x1b[2J\x1b[H"); io::stdout().flush()?; }
"reset" => {
*filters = LiveLogFilters::default();
println!("filters cleared");
}
"pause" => {
filters.paused = true;
println!("paused");
}
"resume" => {
filters.paused = false;
println!("resumed");
}
"clear" => {
print!("\x1b[2J\x1b[H");
io::stdout().flush()?;
}
"quit" | "exit" | "q" => return Ok(false),
"detail" => filters.detail = matches!(value, "on" | "1" | "true"),
"errors" => filters.errors_only = matches!(value, "on" | "1" | "true"),
"slow" => {
filters.slow_ms = if matches!(value, "" | "off" | "*") { None } else { Some(value.parse().context("slow expects milliseconds or off")?) };
filters.slow_ms = if matches!(value, "" | "off" | "*") {
None
} else {
Some(value.parse().context("slow expects milliseconds or off")?)
};
}
"status" => {
if matches!(value, "" | "*" | "off") { filters.status = None; }
else {
ensure!(matches!(value, "1xx" | "2xx" | "3xx" | "4xx" | "5xx") || value.parse::<u16>().ok().is_some_and(|v| (100..=599).contains(&v)), "status expects 100..599 or 1xx..5xx");
if matches!(value, "" | "*" | "off") {
filters.status = None;
} else {
ensure!(
matches!(value, "1xx" | "2xx" | "3xx" | "4xx" | "5xx")
|| value
.parse::<u16>()
.ok()
.is_some_and(|v| (100..=599).contains(&v)),
"status expects 100..599 or 1xx..5xx"
);
filters.status = Some(value.to_ascii_lowercase());
}
}
@@ -378,9 +434,19 @@ fn handle_live_command(
"backend" => set_live_filter(&mut filters.backend, value),
"route" => set_live_filter(&mut filters.route, value),
"client" => set_live_filter(&mut filters.client, value),
"method" => { set_live_filter(&mut filters.method, value); if let Some(v) = filters.method.as_mut() { *v = v.to_ascii_uppercase(); } },
"method" => {
set_live_filter(&mut filters.method, value);
if let Some(v) = filters.method.as_mut() {
*v = v.to_ascii_uppercase();
}
}
"transport" => set_live_filter(&mut filters.transport, value),
"cache" => { set_live_filter(&mut filters.cache, value); if let Some(v) = filters.cache.as_mut() { *v = v.to_ascii_uppercase(); } },
"cache" => {
set_live_filter(&mut filters.cache, value);
if let Some(v) = filters.cache.as_mut() {
*v = v.to_ascii_uppercase();
}
}
"path" => set_live_filter(&mut filters.path_prefix, value),
"show" => {
let id: u64 = value.parse().context("show expects a request id")?;
@@ -391,7 +457,10 @@ fn handle_live_command(
}
_ => bail!("unknown live-log command '{command}' (type help)"),
}
if !matches!(command.as_str(), "help" | "?" | "filters" | "show" | "clear") {
if !matches!(
command.as_str(),
"help" | "?" | "filters" | "show" | "clear"
) {
println!("filters: {}", live_filters_summary(filters));
}
Ok(true)
@@ -406,7 +475,13 @@ fn take_sse_event(buffer: &mut Vec<u8>) -> Option<Vec<u8>> {
let lf = find(b"\n\n").map(|index| (index, 2));
let crlf = find(b"\r\n\r\n").map(|index| (index, 4));
let (index, delimiter) = match (lf, crlf) {
(Some(a), Some(b)) => if a.0 <= b.0 { a } else { b },
(Some(a), Some(b)) => {
if a.0 <= b.0 {
a
} else {
b
}
}
(Some(a), None) => a,
(None, Some(b)) => b,
(None, None) => return None,