use exfiltrate::provider::{Provider, ProviderResult, Row, SnapshotRequest};
use crate::instrument;
use crate::registry;
const WEDGED_AFTER: std::time::Duration = std::time::Duration::from_secs(3);
pub fn install() {
exfiltrate::provider::add_provider(Windows);
exfiltrate::provider::add_provider(MainThread);
}
struct Windows;
impl Provider for Windows {
fn subsystem(&self) -> &'static str {
"windows"
}
fn description(&self) -> &'static str {
"windows this process created: requested geometry, attached surface, last observed size and scale"
}
fn snapshot(&self, request: &SnapshotRequest<'_>) -> ProviderResult {
let wanted: Option<u64> = match request.selector() {
Some(selector) => match selector.parse::<u64>() {
Ok(id) => Some(id),
Err(_) => {
return ProviderResult::Unavailable(format!(
"--id must be a window id; got {selector:?}"
));
}
},
None => None,
};
let (Some(entries), Some((dropped, capacity))) = (registry::entries(), registry::stats())
else {
return ProviderResult::Busy;
};
let mut rows = Vec::new();
for entry in entries {
if request.should_stop() {
return ProviderResult::Partial(rows, "deadline".to_string());
}
if let Some(id) = wanted
&& entry.id != id
{
continue;
}
let mut row = Row::new()
.support("id", entry.id)
.support("origin", entry.origin.name())
.support("open", entry.is_open())
.support("surface_attached", entry.surface_attached)
.support("age_ms", entry.created_at.elapsed().as_millis() as u64);
if !entry.title.is_empty() {
row = row.local("title", entry.title.as_str());
}
if let Some(closed_at) = entry.closed_at {
row = row.support("closed_ms_ago", closed_at.elapsed().as_millis() as u64);
}
if let Some((position, size)) = entry.requested {
row = row
.support("requested_x", position.x())
.support("requested_y", position.y())
.support("requested_width", size.width())
.support("requested_height", size.height());
}
if let Some((size, scale, observed_at)) = entry.last_observed {
row = row
.support("observed_width", size.width())
.support("observed_height", size.height())
.support("observed_scale", scale)
.support("observed_ms_ago", observed_at.elapsed().as_millis() as u64);
}
rows.push(row);
}
if dropped > 0 {
return ProviderResult::Partial(
rows,
format!(
"{dropped} record(s) evicted at a capacity of {capacity}; \
raise APP_WINDOW_REGISTRY_CAPACITY"
),
);
}
ProviderResult::Rows(rows)
}
}
struct MainThread;
impl Provider for MainThread {
fn subsystem(&self) -> &'static str {
"main_thread"
}
fn description(&self) -> &'static str {
"platform event loop: whether it is pumping, and how long it has not been"
}
fn snapshot(&self, request: &SnapshotRequest<'_>) -> ProviderResult {
if let Some(selector) = request.selector() {
return ProviderResult::Unavailable(format!(
"there is one main thread; --id {selector:?} selects nothing"
));
}
let stats = instrument::stats();
instrument::probe();
if !stats.running {
return ProviderResult::Unavailable(
"app_window::application::main has not been called; there is no event loop"
.to_string(),
);
}
let mut row = Row::new()
.support("running", stats.running)
.support("submitted", stats.submitted)
.support("completed", stats.completed)
.support("outstanding", stats.outstanding)
.support("overran_10ms", stats.overran)
.support("slowest_turn_ms", stats.slowest_ms);
if let Some(since) = stats.since_last_turn {
row = row.support("last_turn_ms_ago", since.as_millis() as u64);
}
if let Some(round_trip) = stats.last_probe_round_trip {
row = row.support("probe_round_trip_ms", round_trip.as_millis() as u64);
}
match stats.probe_outstanding {
None => {
row = row.support("responding", true);
ProviderResult::Rows(vec![row])
}
Some(waiting) if waiting < WEDGED_AFTER => {
row = row
.support("responding", true)
.support("probe_waiting_ms", waiting.as_millis() as u64);
ProviderResult::Rows(vec![row])
}
Some(waiting) => {
row = row
.support("responding", false)
.support("probe_waiting_ms", waiting.as_millis() as u64);
ProviderResult::Partial(
vec![row],
format!(
"the main thread has not run a submitted closure for {}ms; \
something is holding it",
waiting.as_millis()
),
)
}
}
}
}