This commit is contained in:
Mateusz Gruszczyński committed 2026-10-04 09:29:10 +02:00
1 parent 2e4aa4df4d
commit 87e571c170
106 files changed
+17952 -6185

No files matched your search

+97 -30
View File
@@ -41,6 +41,8 @@ pub struct Exchange {
pub upstream_status: AtomicU16,
pub upstream_error: Mutex<Option<String>>,
pub client_ip: Mutex<Option<String>>,
pub user_agent: Option<String>,
pub country: Mutex<Option<String>>,
pub started: Instant,
pub status: AtomicU16,
pub cache_status: AtomicU16,
@@ -51,18 +53,28 @@ pub struct Exchange {
pub response_bytes: AtomicU64,
pub metrics: Arc<Metrics>,
pub logs: Arc<Logs>,
pub traffic: Arc<crate::traffic::Analytics>,
pub _permit: OwnedSemaphorePermit,
}
impl Exchange {
pub fn websocket_phase(&self, phase: &'static str) {
if self.websocket_bootstrap.is_some() {
*self.websocket_phase.lock().unwrap_or_else(|e| e.into_inner()) = Some(phase);
*self
.websocket_phase
.lock()
.unwrap_or_else(|e| e.into_inner()) = Some(phase);
}
}
pub fn websocket_error(&self, phase: &'static str, error: &'static str) {
if self.websocket_bootstrap.is_some() {
*self.websocket_phase.lock().unwrap_or_else(|e| e.into_inner()) = Some(phase);
*self.websocket_error.lock().unwrap_or_else(|e| e.into_inner()) = Some(error);
*self
.websocket_phase
.lock()
.unwrap_or_else(|e| e.into_inner()) = Some(phase);
*self
.websocket_error
.lock()
.unwrap_or_else(|e| e.into_inner()) = Some(error);
}
}
pub fn h3_reset(&self, code: &'static str) {
@@ -126,13 +138,71 @@ impl Drop for Exchange {
.unwrap_or_else(|e| e.into_inner())
.as_ref()
.map(|l| l.member.backend.id.clone());
let websocket_phase = *self.websocket_phase.lock().unwrap_or_else(|e| e.into_inner());
let websocket_phase = *self
.websocket_phase
.lock()
.unwrap_or_else(|e| e.into_inner());
let route = self.route.lock().unwrap_or_else(|e| e.into_inner()).clone();
let cache_effective_enabled = *self
.cache_effective_enabled
.lock()
.unwrap_or_else(|e| e.into_inner());
let transform_effective_enabled = *self
.transform_effective_enabled
.lock()
.unwrap_or_else(|e| e.into_inner());
let client_ip = self
.client_ip
.lock()
.unwrap_or_else(|e| e.into_inner())
.clone();
let country = self
.country
.lock()
.unwrap_or_else(|e| e.into_inner())
.clone();
let request_bytes = self.request_bytes.load(Ordering::Relaxed);
let response_bytes = self.response_bytes.load(Ordering::Relaxed);
let duration_ms = duration.as_millis() as u64;
let cache = match self.cache_status.load(Ordering::Relaxed) {
1 => "HIT",
2 => "MISS",
3 => "BYPASS",
_ => "-",
};
let outcome = if failed {
"body_error"
} else if aborted {
"cancelled"
} else if status >= 500 {
"proxy_or_upstream_error"
} else if status == 101 || websocket_phase == Some("tunnel_closed") {
"websocket_closed"
} else {
"complete"
};
if let Some(vhost) = self.vhost.clone() {
self.traffic.push(crate::traffic::Sample {
vhost,
route: route.clone(),
method: self.method.clone(),
path: self.path.clone(),
client_ip: client_ip.clone(),
status,
duration_ms,
request_bytes,
response_bytes,
cache,
user_agent: self.user_agent.clone(),
country: country.clone(),
});
}
self.logs.push(LogEntry {
cache_reason: *self.cache_reason.lock().unwrap_or_else(|e| e.into_inner()),
vhost: self.vhost.clone(),
route: self.route.lock().unwrap_or_else(|e| e.into_inner()).clone(),
cache_effective_enabled: *self.cache_effective_enabled.lock().unwrap_or_else(|e| e.into_inner()),
transform_effective_enabled: *self.transform_effective_enabled.lock().unwrap_or_else(|e| e.into_inner()),
route,
cache_effective_enabled,
transform_effective_enabled,
backend,
id: self.id,
time_ms: now_ms(),
@@ -143,35 +213,29 @@ impl Drop for Exchange {
transport: self.transport,
websocket_bootstrap: self.websocket_bootstrap,
websocket_phase,
websocket_error: *self.websocket_error.lock().unwrap_or_else(|e| e.into_inner()),
websocket_error: *self
.websocket_error
.lock()
.unwrap_or_else(|e| e.into_inner()),
h3_reset_code: *self.h3_reset_code.lock().unwrap_or_else(|e| e.into_inner()),
upstream_status: match self.upstream_status.load(Ordering::Relaxed) {
0 => None,
value => Some(value),
},
upstream_error: self.upstream_error.lock().unwrap_or_else(|e| e.into_inner()).clone(),
client_ip: self.client_ip.lock().unwrap_or_else(|e| e.into_inner()).clone(),
upstream_error: self
.upstream_error
.lock()
.unwrap_or_else(|e| e.into_inner())
.clone(),
client_ip,
user_agent: self.user_agent.clone(),
country,
status,
duration_ms: duration.as_millis() as u64,
cache: match self.cache_status.load(Ordering::Relaxed) {
1 => "HIT",
2 => "MISS",
3 => "BYPASS",
_ => "-",
},
request_bytes: self.request_bytes.load(Ordering::Relaxed),
response_bytes: self.response_bytes.load(Ordering::Relaxed),
outcome: if failed {
"body_error"
} else if aborted {
"cancelled"
} else if status >= 500 {
"proxy_or_upstream_error"
} else if status == 101 || websocket_phase == Some("tunnel_closed") {
"websocket_closed"
} else {
"complete"
},
duration_ms,
cache,
request_bytes,
response_bytes,
outcome,
});
}
}
@@ -332,6 +396,8 @@ mod tests {
upstream_status: AtomicU16::new(0),
upstream_error: Mutex::new(None),
client_ip: Mutex::new(Some("127.0.0.1".into())),
user_agent: Some("RustProxy-Test/1.0".into()),
country: Mutex::new(Some("PL".into())),
started: Instant::now(),
status: AtomicU16::new(200),
cache_status: AtomicU16::new(0),
@@ -342,6 +408,7 @@ mod tests {
response_bytes: AtomicU64::new(0),
metrics,
logs: Arc::new(Logs::default()),
traffic: crate::traffic::Analytics::start(tokio_util::sync::CancellationToken::new()),
_permit: permit,
});
(exchange, slots)