diff --git a/src/http/mod.rs b/src/http/mod.rs index 2128293..a91ef71 100644 --- a/src/http/mod.rs +++ b/src/http/mod.rs @@ -731,6 +731,8 @@ impl Service> for HttpService { Ok(upgraded) => { tracing::info!("WebSocket connection established from {}", addr); // Track connection + let _connection_timer = + metrics_clone.as_ref().map(|m| m.start_connection_timer()); if let Some(ref m) = metrics_clone { m.connection_tracker().on_connect(addr.ip()); m.record_websocket_connection(); diff --git a/tests/websocket_metrics.rs b/tests/websocket_metrics.rs new file mode 100644 index 0000000..4b3ff04 --- /dev/null +++ b/tests/websocket_metrics.rs @@ -0,0 +1,40 @@ +//! WebSocket lifecycle metrics scenarios. + +mod common; + +use std::time::{Duration, Instant}; + +use common::{sync_helpers::fetch_metrics, TestRelay}; + +fn connection_duration_count(metrics: &str) -> Option { + metrics.lines().find_map(|line| { + line.strip_prefix("ngit_websocket_connection_duration_seconds_count ")? + .parse() + .ok() + }) +} + +#[tokio::test] +async fn closed_websocket_records_its_connection_duration() { + let relay = TestRelay::start().await; + let (mut stream, _) = tokio_tungstenite::connect_async(relay.url()) + .await + .expect("connect to relay"); + + stream.close(None).await.expect("close websocket"); + + let deadline = Instant::now() + Duration::from_secs(5); + loop { + let metrics = fetch_metrics(relay.url()).await.expect("fetch metrics"); + if connection_duration_count(&metrics) == Some(1) { + break; + } + assert!( + Instant::now() < deadline, + "closed connection was not observed in duration histogram: {metrics}" + ); + tokio::time::sleep(Duration::from_millis(25)).await; + } + + relay.stop().await; +}