feat(metrics): add frontend and backend protocol distribution metrics

This commit is contained in:
2026-04-04 16:52:25 +00:00
parent a55ff20391
commit b04eb0ab17
7 changed files with 295 additions and 2 deletions

View File

@@ -110,6 +110,36 @@ impl Drop for ActiveRequestGuard {
}
}
/// RAII guard that calls frontend_protocol_closed or backend_protocol_closed on drop.
/// Ensures active protocol counters are decremented on all exit paths.
pub(crate) struct ProtocolGuard {
metrics: Arc<MetricsCollector>,
version: &'static str,
is_frontend: bool,
}
impl ProtocolGuard {
pub fn frontend(metrics: Arc<MetricsCollector>, version: &'static str) -> Self {
metrics.frontend_protocol_opened(version);
Self { metrics, version, is_frontend: true }
}
pub fn backend(metrics: Arc<MetricsCollector>, version: &'static str) -> Self {
metrics.backend_protocol_opened(version);
Self { metrics, version, is_frontend: false }
}
}
impl Drop for ProtocolGuard {
fn drop(&mut self) {
if self.is_frontend {
self.metrics.frontend_protocol_closed(self.version);
} else {
self.metrics.backend_protocol_closed(self.version);
}
}
}
/// Backend stream that can be either plain TCP or TLS-wrapped.
/// Used for `terminate-and-reencrypt` mode where the backend requires TLS.
pub(crate) enum BackendStream {
@@ -625,6 +655,18 @@ impl HttpProxyService {
.map(|p| p.as_str().eq_ignore_ascii_case("websocket"))
.unwrap_or(false);
// Track frontend protocol for distribution metrics (h1/h2/h3/ws)
let frontend_proto: &'static str = if is_h1_websocket || is_h2_websocket {
"ws"
} else {
match req.version() {
hyper::Version::HTTP_2 => "h2",
hyper::Version::HTTP_3 => "h3",
_ => "h1", // HTTP/1.0, HTTP/1.1
}
};
let _frontend_proto_guard = ProtocolGuard::frontend(Arc::clone(&self.metrics), frontend_proto);
if is_h1_websocket || is_h2_websocket {
let result = self.handle_websocket_upgrade(
req, peer_addr, &upstream, route_match.route, route_id, &upstream_key, cancel, &ip_str, is_h2_websocket,
@@ -2383,6 +2425,8 @@ impl HttpProxyService {
selector: upstream_selector,
key: upstream_key_owned.clone(),
};
// Track backend WebSocket connection — guard decrements on tunnel close
let _backend_ws_guard = ProtocolGuard::backend(Arc::clone(&metrics), "ws");
let client_upgraded = match on_client_upgrade.await {
Ok(upgraded) => upgraded,