Skip to content

Add connection-level timing metrics and key update tracking to Stats#2416

Open
devin-cog wants to merge 1 commit into
cloudflare:masterfrom
devin-cog:devin/1774400362-connection-timing-metrics
Open

Add connection-level timing metrics and key update tracking to Stats#2416
devin-cog wants to merge 1 commit into
cloudflare:masterfrom
devin-cog:devin/1774400362-connection-timing-metrics

Conversation

@devin-cog
Copy link
Copy Markdown

@devin-cog devin-cog commented Mar 25, 2026

Summary

Add new fields to the public Stats struct for production observability:

  • handshake_duration: Option<Duration> — time from connection creation to handshake completion, None if handshake hasn't completed
  • key_update_count: u64 — number of 1-RTT key updates
  • peer_max_idle_timeout: Option<Duration> — the peer's max idle timeout from transport params
  • connection_duration: Duration — wall-clock time since connection creation

Implementation details

  • Track created_at: Instant and handshake_completed_at: Option<Instant> on Connection, initialized in with_tls() and set when handshake completes
  • Track key_update_count: u64 on Connection, incremented when a peer-initiated key update is verified
  • Populate new Stats fields in stats() method
  • Update Debug impl for Stats to include new fields
  • Expose via FFI: new fields in the C Stats struct plus standalone query functions (quiche_conn_stats_handshake_duration_ms, quiche_conn_stats_key_update_count, quiche_conn_stats_peer_max_idle_timeout_ms, quiche_conn_stats_connection_duration_ms)
  • Add unit tests verifying pre/post handshake behavior

Verification

  • cargo build succeeds
  • cargo +nightly fmt -- --check clean
  • cargo clippy --features=boringssl-vendored --workspace -- -D warnings clean
  • All 963 quiche tests pass (including 4 new tests)

Review & Testing Checklist for Human

  • Verify handshake_completed_at is set at the right place — it's set right after self.handshake.is_completed() returns true
  • Verify key_update_count increment location — placed after key update is verified (after successful decryption with new keys), per RFC 9001
  • Check FFI return type conventions — using i64 with -1 sentinel for optional durations; confirm this matches downstream C consumer expectations
  • Run the full test suite in your CI environment to verify no regressions

Notes

  • The only pre-existing test failure is integration_tests::test_so_mark_receive_data in tokio-quiche, which requires special socket permissions and is unrelated to this change
  • peer_max_idle_timeout returns None when the peer's transport params haven't been parsed yet or when max_idle_timeout is 0 (which per RFC 9000 means no timeout)

Add new fields to the public Stats struct for production observability:
- handshake_duration: time from connection creation to handshake completion
- key_update_count: number of 1-RTT key updates
- peer_max_idle_timeout: peer's max idle timeout from transport params
- connection_duration: wall-clock time since connection creation

Implementation details:
- Track created_at (Instant) and handshake_completed_at (Option<Instant>)
  on Connection, initialized in with_tls() and set on handshake completion
- Track key_update_count on Connection, incremented when a peer-initiated
  key update is verified
- Populate new Stats fields in stats() method
- Update Debug impl for Stats to include new fields
- Expose via FFI: new fields in the C Stats struct plus standalone
  query functions (quiche_conn_stats_handshake_duration_ms, etc.)
- Add unit tests verifying pre/post handshake behavior

Co-Authored-By: Staging-Devin AI <166158716+staging-devin-ai-integration[bot]@users.noreply.github.com>
@devin-cog devin-cog requested a review from a team as a code owner March 25, 2026 01:13
Comment thread quiche/src/lib.rs

if let Some(hs) = self.handshake_duration {
write!(f, " handshake_duration={:?}", hs)?;
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also add key_update_count ?

Comment thread quiche/src/lib.rs
} else {
None
},
connection_duration: self.created_at.elapsed(),
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would have considered providing the creation time since that's also an important piece of info when logging info on a connection. The caller can compute duration on it's own based on that.

I could see there being some challenges with logging wanting to use SystemTime instead of Monotonic time.

Comment thread quiche/src/lib.rs
tx_buffered_state: self.tx_buffered_state,
handshake_duration: self
.handshake_completed_at
.map(|completed| completed.duration_since(self.created_at)),
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should the connection store the handshake_duration instead of handshake_completed_at?

Comment thread quiche/src/ffi.rs

/// Returns the handshake duration in milliseconds, or -1 if the
/// handshake has not yet completed.
#[no_mangle]
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are the extra ffi functions below needed despite the data being available via quiche_conn_stats above?

@antoniovicente
Copy link
Copy Markdown
Contributor

Thanks for the stats improvements. See comments above.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants