1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
use super::TorTransport;
use std::time::Duration;
use tokio::time::Instant;
use tracing::{info, warn};
impl TorTransport {
/// Spawn a background task that periodically queries the Tor control
/// port for daemon status and caches the result.
pub(super) fn spawn_monitoring_task(&mut self) {
let Some(client) = self.control_client.clone() else {
return;
};
let cache = self.cached_monitoring.clone();
let stats = self.stats.clone();
let transport_id = self.transport_id;
let handle = tokio::spawn(async move {
let mut interval = tokio::time::interval(Duration::from_secs(10));
let mut last_bootstrap: u8 = 0;
let mut last_liveness = String::new();
let mut was_dormant = false;
let mut stall_warned = false;
let started_at = Instant::now();
loop {
interval.tick().await;
let mut guard = client.lock().await;
match guard.monitoring_snapshot().await {
Ok(info) => {
// Log bootstrap milestones
for &milestone in &[25u8, 50, 75, 100] {
if info.bootstrap >= milestone && last_bootstrap < milestone {
info!(
transport_id = %transport_id,
bootstrap = info.bootstrap,
"Tor bootstrap {}%",
milestone
);
}
}
// Bootstrap stall warning
if info.bootstrap < 100
&& started_at.elapsed() > Duration::from_secs(60)
&& !stall_warned
{
warn!(
transport_id = %transport_id,
bootstrap = info.bootstrap,
"Tor bootstrap stalled — not at 100% after 60s"
);
stall_warned = true;
}
if info.bootstrap == 100 {
stall_warned = false;
}
last_bootstrap = info.bootstrap;
// Network liveness transitions
if !last_liveness.is_empty() && info.network_liveness != last_liveness {
warn!(
transport_id = %transport_id,
from = %last_liveness,
to = %info.network_liveness,
"Tor network liveness changed"
);
}
last_liveness = info.network_liveness.clone();
// Dormant mode entry
if info.dormant && !was_dormant {
warn!(
transport_id = %transport_id,
"Tor daemon entered dormant mode"
);
}
was_dormant = info.dormant;
if let Ok(mut w) = cache.write() {
*w = Some(info);
}
}
Err(e) => {
stats.record_control_error();
warn!(
transport_id = %transport_id,
error = %e,
"Tor monitoring query failed"
);
}
}
}
});
self.monitoring_task = Some(handle);
}
}